[SHELL32] -CRecycleBin: Factor out a new class called CRecyclerDropTarget, which...
authorGiannis Adamopoulos <gadamopoulos@reactos.org>
Tue, 22 Aug 2017 13:50:25 +0000 (13:50 +0000)
committerGiannis Adamopoulos <gadamopoulos@reactos.org>
Tue, 22 Aug 2017 13:50:25 +0000 (13:50 +0000)
svn path=/trunk/; revision=75640

reactos/dll/win32/shell32/CDefaultContextMenu.cpp
reactos/dll/win32/shell32/CMakeLists.txt
reactos/dll/win32/shell32/droptargets/CRecyclerDropTarget.cpp [new file with mode: 0644]
reactos/dll/win32/shell32/folders/CRecycleBin.cpp
reactos/dll/win32/shell32/folders/CRecycleBin.h

index 172b478..13d084f 100644 (file)
@@ -810,7 +810,13 @@ HRESULT CDefaultContextMenu::DoDelete(LPCMINVOKECOMMANDINFO lpcmi)
     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;
 }
 
index cb42fc3..46af5e6 100644 (file)
@@ -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 (file)
index 0000000..9a46c56
--- /dev/null
@@ -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);
+}
index 96790c7..8b60896 100644 (file)
@@ -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<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))
     {
         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<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);
-}
-
 /*************************************************************************
  *              SHEmptyRecycleBinA (SHELL32.@)
  */
index 758860b..1f3ea7b 100644 (file)
 #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 @@ 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()
 };