Author: gadamopoulos Date: Tue Aug 22 13:50:25 2017 New Revision: 75640 URL: http://svn.reactos.org/svn/reactos?rev=75640&view=rev Log: [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.
Added: trunk/reactos/dll/win32/shell32/droptargets/CRecyclerDropTarget.cpp (with props) Modified: trunk/reactos/dll/win32/shell32/CDefaultContextMenu.cpp trunk/reactos/dll/win32/shell32/CMakeLists.txt trunk/reactos/dll/win32/shell32/folders/CRecycleBin.cpp trunk/reactos/dll/win32/shell32/folders/CRecycleBin.h Modified: trunk/reactos/dll/win32/shell32/CDefaultContextMenu.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/CDefaultContextMenu.cpp?rev=75640&r1=75639&r2=75640&view=diff ============================================================================== --- trunk/reactos/dll/win32/shell32/CDefaultContextMenu.cpp [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shell32/CDefaultContextMenu.cpp [iso-8859-1] Tue Aug 22 13:50:25 2017 @@ -810,7 +810,13 @@ if (!m_cidl || !m_pDataObj) return E_FAIL; - DoDeleteAsync(m_pDataObj, lpcmi->fMask); + CComPtr<IDropTarget> 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; } Modified: trunk/reactos/dll/win32/shell32/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/CMakeLists.txt?rev=75640&r1=75639&r2=75640&view=diff ============================================================================== --- trunk/reactos/dll/win32/shell32/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shell32/CMakeLists.txt [iso-8859-1] Tue Aug 22 13:50:25 2017 @@ -57,6 +57,7 @@ folders/CRegFolder.cpp droptargets/CexeDropHandler.cpp droptargets/CFSDropTarget.cpp + droptargets/CRecyclerDropTarget.cpp shlexec.cpp shlfileop.cpp shlfolder.cpp Added: trunk/reactos/dll/win32/shell32/droptargets/CRecyclerDropTarget.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/droptargets/CRecyclerDropTarget.cpp?rev=75640 ============================================================================== --- trunk/reactos/dll/win32/shell32/droptargets/CRecyclerDropTarget.cpp (added) +++ trunk/reactos/dll/win32/shell32/droptargets/CRecyclerDropTarget.cpp [iso-8859-1] Tue Aug 22 13:50:25 2017 @@ -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 <precomp.h> + +WINE_DEFAULT_DEBUG_CHANNEL (shell); + +class CRecyclerDropTarget : + public CComObjectRootEx<CComMultiThreadModelNoCS>, + 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<DeleteThreadData*>(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<DeleteThreadData*>(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<CRecyclerDropTarget>(riid, ppvOut); +} Propchange: trunk/reactos/dll/win32/shell32/droptargets/CRecyclerDropTarget.cpp ------------------------------------------------------------------------------ svn:eol-style = native Modified: trunk/reactos/dll/win32/shell32/folders/CRecycleBin.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/folders/CRecycleBin.cpp?rev=75640&r1=75639&r2=75640&view=diff ============================================================================== --- trunk/reactos/dll/win32/shell32/folders/CRecycleBin.cpp [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shell32/folders/CRecycleBin.cpp [iso-8859-1] Tue Aug 22 13:50:25 2017 @@ -410,29 +410,13 @@ 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 @@ 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 @@ } else return hr; + TRACE ("-- (%p)->(interface=%p)\n", this, ppv); return hr; @@ -599,12 +584,6 @@ if ((IsEqualIID (riid, IID_IContextMenu) || IsEqualIID(riid, IID_IContextMenu2)) && (cidl >= 1)) { hr = ShellObjectCreatorInit<CRecycleBinItemContextMenu>(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)) { @@ -983,163 +962,7 @@ { 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<DeleteThreadData*>(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<DeleteThreadData*>(HeapAlloc(GetProcessHeap(), 0, sizeof(DeleteThreadData))); - data->fMask = fMask; - CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pda, &data->s); - SHCreateThread(DoDeleteThreadProc, data, NULL, NULL); + return S_OK; } /************************************************************************* Modified: trunk/reactos/dll/win32/shell32/folders/CRecycleBin.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/shell32/folders/CRecycleBin.h?rev=75640&r1=75639&r2=75640&view=diff ============================================================================== --- trunk/reactos/dll/win32/shell32/folders/CRecycleBin.h [iso-8859-1] (original) +++ trunk/reactos/dll/win32/shell32/folders/CRecycleBin.h [iso-8859-1] Tue Aug 22 13:50:25 2017 @@ -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<CRecycleBin, &CLSID_RecycleBin>, @@ -34,16 +33,11 @@ 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 @@ // 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 @@ 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() };