From 524ce41fa24c77b631a75b59664eb7dc7d53a82e Mon Sep 17 00:00:00 2001 From: Giannis Adamopoulos Date: Tue, 22 Aug 2017 13:50:25 +0000 Subject: [PATCH] [SHELL32] -CRecycleBin: Factor out a new class called CRecyclerDropTarget, which will take the data object and call SHFileOperation for its contents. Add a noisy print to show the parameters passed in SHFileOperation and make it to always use DROPEFFECT_MOVE. Make CDefaultContextMenu use the new drop target in order to delete a file. svn path=/trunk/; revision=75640 --- .../dll/win32/shell32/CDefaultContextMenu.cpp | 8 +- reactos/dll/win32/shell32/CMakeLists.txt | 1 + .../droptargets/CRecyclerDropTarget.cpp | 184 ++++++++++++++++++ .../dll/win32/shell32/folders/CRecycleBin.cpp | 181 +---------------- .../dll/win32/shell32/folders/CRecycleBin.h | 15 +- 5 files changed, 195 insertions(+), 194 deletions(-) create mode 100644 reactos/dll/win32/shell32/droptargets/CRecyclerDropTarget.cpp diff --git a/reactos/dll/win32/shell32/CDefaultContextMenu.cpp b/reactos/dll/win32/shell32/CDefaultContextMenu.cpp index 172b478d363..13d084ffbbe 100644 --- a/reactos/dll/win32/shell32/CDefaultContextMenu.cpp +++ b/reactos/dll/win32/shell32/CDefaultContextMenu.cpp @@ -810,7 +810,13 @@ HRESULT CDefaultContextMenu::DoDelete(LPCMINVOKECOMMANDINFO lpcmi) if (!m_cidl || !m_pDataObj) return E_FAIL; - DoDeleteAsync(m_pDataObj, lpcmi->fMask); + CComPtr pDT; + HRESULT hr = CRecyclerDropTarget_CreateInstance(IID_PPV_ARG(IDropTarget, &pDT)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + SHSimulateDrop(pDT, m_pDataObj, 0, NULL, NULL); + return S_OK; } diff --git a/reactos/dll/win32/shell32/CMakeLists.txt b/reactos/dll/win32/shell32/CMakeLists.txt index cb42fc3f2a2..46af5e6e323 100644 --- a/reactos/dll/win32/shell32/CMakeLists.txt +++ b/reactos/dll/win32/shell32/CMakeLists.txt @@ -57,6 +57,7 @@ list(APPEND SOURCE folders/CRegFolder.cpp droptargets/CexeDropHandler.cpp droptargets/CFSDropTarget.cpp + droptargets/CRecyclerDropTarget.cpp shlexec.cpp shlfileop.cpp shlfolder.cpp diff --git a/reactos/dll/win32/shell32/droptargets/CRecyclerDropTarget.cpp b/reactos/dll/win32/shell32/droptargets/CRecyclerDropTarget.cpp new file mode 100644 index 00000000000..9a46c56b5bc --- /dev/null +++ b/reactos/dll/win32/shell32/droptargets/CRecyclerDropTarget.cpp @@ -0,0 +1,184 @@ +/* + * Trash virtual folder support. The trashing engine is implemented in trash.c + * + * Copyright (C) 2006 Mikolaj Zalewski + * Copyright (C) 2009 Andrew Hill + * Copyright (C) 2017 Giannis Adamopoulos + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL (shell); + +class CRecyclerDropTarget : + public CComObjectRootEx, + public IDropTarget +{ + private: + BOOL fAcceptFmt; /* flag for pending Drop */ + UINT cfShellIDList; + + static HRESULT _DoDeleteDataObject(IDataObject *pda, DWORD fMask) + { + HRESULT hr; + STGMEDIUM medium; + FORMATETC formatetc; + InitFormatEtc (formatetc, CF_HDROP, TYMED_HGLOBAL); + hr = pda->GetData(&formatetc, &medium); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + LPDROPFILES lpdf = (LPDROPFILES) GlobalLock(medium.hGlobal); + if (!lpdf) + { + ERR("Error locking global\n"); + return E_FAIL; + } + + /* Delete them */ + SHFILEOPSTRUCTW FileOp; + ZeroMemory(&FileOp, sizeof(FileOp)); + FileOp.wFunc = FO_DELETE; + FileOp.pFrom = (LPWSTR) (((byte*) lpdf) + lpdf->pFiles);; + if ((fMask & CMIC_MASK_SHIFT_DOWN) == 0) + FileOp.fFlags = FOF_ALLOWUNDO; + ERR("Deleting file (just the first) = %s, allowundo: %d\n", debugstr_w(FileOp.pFrom), (FileOp.fFlags == FOF_ALLOWUNDO)); + + if (SHFileOperationW(&FileOp) != 0) + { + ERR("SHFileOperation failed with 0x%x\n", GetLastError()); + hr = E_FAIL; + } + + ReleaseStgMedium(&medium); + + return hr; + } + + struct DeleteThreadData { + IStream *s; + DWORD fMask; + }; + + static DWORD WINAPI _DoDeleteThreadProc(LPVOID lpParameter) + { + DeleteThreadData *data = static_cast(lpParameter); + CoInitialize(NULL); + IDataObject *pDataObject; + HRESULT hr = CoGetInterfaceAndReleaseStream (data->s, IID_PPV_ARG(IDataObject, &pDataObject)); + if (SUCCEEDED(hr)) + { + _DoDeleteDataObject(pDataObject, data->fMask); + } + pDataObject->Release(); + CoUninitialize(); + HeapFree(GetProcessHeap(), 0, data); + return 0; + } + + static void _DoDeleteAsync(IDataObject *pda, DWORD fMask) + { + DeleteThreadData *data = static_cast(HeapAlloc(GetProcessHeap(), 0, sizeof(DeleteThreadData))); + data->fMask = fMask; + CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pda, &data->s); + SHCreateThread(_DoDeleteThreadProc, data, NULL, NULL); + } + + public: + + CRecyclerDropTarget() + { + fAcceptFmt = FALSE; + cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST); + } + + HRESULT WINAPI DragEnter(IDataObject *pDataObject, + DWORD dwKeyState, POINTL pt, DWORD *pdwEffect) + { + TRACE("Recycle bin drag over (%p)\n", this); + /* The recycle bin accepts pretty much everything, and sets a CSIDL flag. */ + fAcceptFmt = TRUE; + + *pdwEffect = DROPEFFECT_MOVE; + return S_OK; + } + + HRESULT WINAPI DragOver(DWORD dwKeyState, POINTL pt, DWORD *pdwEffect) + { + TRACE("(%p)\n", this); + + if (!pdwEffect) + return E_INVALIDARG; + + *pdwEffect = DROPEFFECT_MOVE; + + return S_OK; + } + + HRESULT WINAPI DragLeave() + { + TRACE("(%p)\n", this); + + fAcceptFmt = FALSE; + + return S_OK; + } + + HRESULT WINAPI Drop(IDataObject *pDataObject, + DWORD dwKeyState, POINTL pt, DWORD *pdwEffect) + { + TRACE("(%p) object dropped on recycle bin, effect %u\n", this, *pdwEffect); + + /* TODO: pdwEffect should be read and make the drop object be permanently deleted in the move case (shift held) */ + + FORMATETC fmt; + TRACE("(%p)->(DataObject=%p)\n", this, pDataObject); + InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL); + + /* Handle cfShellIDList Drop objects here, otherwise send the approriate message to other software */ + if (SUCCEEDED(pDataObject->QueryGetData(&fmt))) + { + DWORD fMask = 0; + + if ((dwKeyState & MK_SHIFT) == MK_SHIFT) + fMask |= CMIC_MASK_SHIFT_DOWN; + + _DoDeleteAsync(pDataObject, fMask); + } + else + { + /* + * TODO call SetData on the data object with format CFSTR_TARGETCLSID + * set to the Recycle Bin's class identifier CLSID_RecycleBin. + */ + } + return S_OK; + } + + DECLARE_NOT_AGGREGATABLE(CRecyclerDropTarget) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CRecyclerDropTarget) + COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget) + END_COM_MAP() +}; + +HRESULT CRecyclerDropTarget_CreateInstance(REFIID riid, LPVOID * ppvOut) +{ + return ShellObjectCreator(riid, ppvOut); +} diff --git a/reactos/dll/win32/shell32/folders/CRecycleBin.cpp b/reactos/dll/win32/shell32/folders/CRecycleBin.cpp index 96790c767c3..8b60896f00d 100644 --- a/reactos/dll/win32/shell32/folders/CRecycleBin.cpp +++ b/reactos/dll/win32/shell32/folders/CRecycleBin.cpp @@ -410,29 +410,13 @@ HRESULT WINAPI CRecycleBinItemContextMenu::HandleMenuMsg(UINT uMsg, WPARAM wPara return E_NOTIMPL; } -/************************************************************************** -* registers clipboardformat once -*/ -void CRecycleBin::SF_RegisterClipFmt() -{ - TRACE ("(%p)\n", this); - - if (!cfShellIDList) - cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST); -} - CRecycleBin::CRecycleBin() { pidl = NULL; - iIdEmpty = 0; - cfShellIDList = 0; - SF_RegisterClipFmt(); - fAcceptFmt = FALSE; } CRecycleBin::~CRecycleBin() { - /* InterlockedDecrement(&objCount);*/ SHFree(pidl); } @@ -556,7 +540,7 @@ HRESULT WINAPI CRecycleBin::CreateViewObject(HWND hwndOwner, REFIID riid, void * if (IsEqualIID (riid, IID_IDropTarget)) { - hr = this->QueryInterface (IID_IDropTarget, ppv); + hr = CRecyclerDropTarget_CreateInstance(riid, ppv); } else if (IsEqualIID (riid, IID_IContextMenu) || IsEqualIID (riid, IID_IContextMenu2)) { @@ -569,6 +553,7 @@ HRESULT WINAPI CRecycleBin::CreateViewObject(HWND hwndOwner, REFIID riid, void * } else return hr; + TRACE ("-- (%p)->(interface=%p)\n", this, ppv); return hr; @@ -600,12 +585,6 @@ HRESULT WINAPI CRecycleBin::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_C { hr = ShellObjectCreatorInit(apidl[0], riid, &pObj); } - else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1)) - { - IDropTarget * pDt = NULL; - hr = QueryInterface(IID_PPV_ARG(IDropTarget, &pDt)); - pObj = pDt; - } else if((IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && (cidl == 1)) { hr = CRecyclerExtractIcon_CreateInstance(apidl[0], riid, &pObj); @@ -983,165 +962,9 @@ EXTERN_C HRESULT WINAPI SHUpdateRecycleBinIcon(void) { FIXME("stub\n"); - - return S_OK; } -/**************************************************************************** - * IDropTarget implementation - */ -BOOL CRecycleBin::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect) -{ - /* TODO on shift we should delete, we should update the cursor manager to show this. */ - - DWORD dwEffect = DROPEFFECT_COPY; - - *pdwEffect = DROPEFFECT_NONE; - - if (fAcceptFmt) { /* Does our interpretation of the keystate ... */ - *pdwEffect = KeyStateToDropEffect (dwKeyState); - - if (*pdwEffect == DROPEFFECT_NONE) - *pdwEffect = dwEffect; - - /* ... matches the desired effect ? */ - if (dwEffect & *pdwEffect) { - return TRUE; - } - } - return FALSE; -} - -HRESULT WINAPI CRecycleBin::DragEnter(IDataObject *pDataObject, - DWORD dwKeyState, POINTL pt, DWORD *pdwEffect) -{ - TRACE("Recycle bin drag over (%p)\n", this); - /* The recycle bin accepts pretty much everything, and sets a CSIDL flag. */ - fAcceptFmt = TRUE; - - QueryDrop(dwKeyState, pdwEffect); - return S_OK; -} - -HRESULT WINAPI CRecycleBin::DragOver(DWORD dwKeyState, POINTL pt, - DWORD *pdwEffect) -{ - TRACE("(%p)\n", this); - - if (!pdwEffect) - return E_INVALIDARG; - - QueryDrop(dwKeyState, pdwEffect); - - return S_OK; -} - -HRESULT WINAPI CRecycleBin::DragLeave() -{ - TRACE("(%p)\n", this); - - fAcceptFmt = FALSE; - - return S_OK; -} - -HRESULT WINAPI CRecycleBin::Drop(IDataObject *pDataObject, - DWORD dwKeyState, POINTL pt, DWORD *pdwEffect) -{ - TRACE("(%p) object dropped on recycle bin, effect %u\n", this, *pdwEffect); - - /* TODO: pdwEffect should be read and make the drop object be permanently deleted in the move case (shift held) */ - - FORMATETC fmt; - TRACE("(%p)->(DataObject=%p)\n", this, pDataObject); - InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL); - - /* Handle cfShellIDList Drop objects here, otherwise send the approriate message to other software */ - if (SUCCEEDED(pDataObject->QueryGetData(&fmt))) - { - DWORD fMask = 0; - - if ((dwKeyState & MK_SHIFT) == MK_SHIFT) - fMask |= CMIC_MASK_SHIFT_DOWN; - - DoDeleteAsync(pDataObject, fMask); - } - else - { - /* - * TODO call SetData on the data object with format CFSTR_TARGETCLSID - * set to the Recycle Bin's class identifier CLSID_RecycleBin. - */ - } - return S_OK; -} - -HRESULT WINAPI DoDeleteDataObject(IDataObject *pda, DWORD fMask) -{ - HRESULT hr; - STGMEDIUM medium; - FORMATETC formatetc; - InitFormatEtc (formatetc, CF_HDROP, TYMED_HGLOBAL); - hr = pda->GetData(&formatetc, &medium); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - LPDROPFILES lpdf = (LPDROPFILES) GlobalLock(medium.hGlobal); - if (!lpdf) - { - ERR("Error locking global\n"); - return E_FAIL; - } - - /* Delete them */ - SHFILEOPSTRUCTW FileOp; - ZeroMemory(&FileOp, sizeof(FileOp)); - FileOp.wFunc = FO_DELETE; - FileOp.pFrom = (LPWSTR) (((byte*) lpdf) + lpdf->pFiles);; - if ((fMask & CMIC_MASK_SHIFT_DOWN) == 0) - FileOp.fFlags = FOF_ALLOWUNDO; - - if (SHFileOperationW(&FileOp) != 0) - { - ERR("SHFileOperation failed with 0x%x\n", GetLastError()); - hr = E_FAIL; - } - - ReleaseStgMedium(&medium); - - return hr; -} - -struct DeleteThreadData { - IStream *s; - DWORD fMask; -}; - -DWORD WINAPI DoDeleteThreadProc(LPVOID lpParameter) -{ - DeleteThreadData *data = static_cast(lpParameter); - CoInitialize(NULL); - IDataObject *pDataObject; - HRESULT hr = CoGetInterfaceAndReleaseStream (data->s, IID_PPV_ARG(IDataObject, &pDataObject)); - if (SUCCEEDED(hr)) - { - DoDeleteDataObject(pDataObject, data->fMask); - } - pDataObject->Release(); - CoUninitialize(); - HeapFree(GetProcessHeap(), 0, data); - return 0; -} - -void DoDeleteAsync(IDataObject *pda, DWORD fMask) -{ - DeleteThreadData *data = static_cast(HeapAlloc(GetProcessHeap(), 0, sizeof(DeleteThreadData))); - data->fMask = fMask; - CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pda, &data->s); - SHCreateThread(DoDeleteThreadProc, data, NULL, NULL); -} - /************************************************************************* * SHEmptyRecycleBinA (SHELL32.@) */ diff --git a/reactos/dll/win32/shell32/folders/CRecycleBin.h b/reactos/dll/win32/shell32/folders/CRecycleBin.h index 758860b955a..1f3ea7bc784 100644 --- a/reactos/dll/win32/shell32/folders/CRecycleBin.h +++ b/reactos/dll/win32/shell32/folders/CRecycleBin.h @@ -22,10 +22,9 @@ #ifndef _SHFLDR_RECYCLEBIN_H_ #define _SHFLDR_RECYCLEBIN_H_ -void DoDeleteAsync(IDataObject *pda, DWORD fMask); - BOOL TRASH_CanTrashFile(LPCWSTR wszPath); BOOL TRASH_TrashFile(LPCWSTR wszPath); +HRESULT CRecyclerDropTarget_CreateInstance(REFIID riid, LPVOID * ppvOut); class CRecycleBin : public CComCoClass, @@ -34,16 +33,11 @@ class CRecycleBin : public IPersistFolder2, public IContextMenu, public IShellPropSheetExt, - public IDropTarget, public IShellExtInit { private: LPITEMIDLIST pidl; INT iIdEmpty; - UINT cfShellIDList; - void SF_RegisterClipFmt(); - BOOL fAcceptFmt; /* flag for pending Drop */ - BOOL QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect); BOOL RecycleBinIsEmpty(); public: @@ -86,12 +80,6 @@ class CRecycleBin : // IShellPropSheetExt virtual HRESULT WINAPI AddPages(LPFNSVADDPROPSHEETPAGE pfnAddPage, LPARAM lParam); virtual HRESULT WINAPI ReplacePage(EXPPS uPageID, LPFNSVADDPROPSHEETPAGE pfnReplaceWith, LPARAM lParam); - - // IDropTarget - virtual HRESULT WINAPI DragEnter(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect); - virtual HRESULT WINAPI DragOver(DWORD dwKeyState, POINTL pt, DWORD *pdwEffect); - virtual HRESULT WINAPI DragLeave(); - virtual HRESULT WINAPI Drop(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect); // IShellExtInit virtual HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID); @@ -108,7 +96,6 @@ class CRecycleBin : COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) COM_INTERFACE_ENTRY_IID(IID_IShellPropSheetExt, IShellPropSheetExt) - COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget) COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit) END_COM_MAP() };