1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Trash virtual folder support. The trashing engine is implemented in trash.c
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * Copyright (C) 2006 Mikolaj Zalewski
5c2c66affSColin Finck  * Copyright (C) 2009 Andrew Hill
6c2c66affSColin Finck  * Copyright (C) 2017 Giannis Adamopoulos
7c2c66affSColin Finck  *
8c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
9c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
10c2c66affSColin Finck  * License as published by the Free Software Foundation; either
11c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
12c2c66affSColin Finck  *
13c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
14c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16c2c66affSColin Finck  * Lesser General Public License for more details.
17c2c66affSColin Finck  *
18c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
19c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
20c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21c2c66affSColin Finck  */
22c2c66affSColin Finck 
23c2c66affSColin Finck #include <precomp.h>
24c2c66affSColin Finck 
25c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL (shell);
26c2c66affSColin Finck 
27c2c66affSColin Finck class CRecyclerDropTarget :
28c2c66affSColin Finck     public CComObjectRootEx<CComMultiThreadModelNoCS>,
29c2c66affSColin Finck     public IDropTarget
30c2c66affSColin Finck {
31c2c66affSColin Finck     private:
32c2c66affSColin Finck         BOOL fAcceptFmt;       /* flag for pending Drop */
33c2c66affSColin Finck         UINT cfShellIDList;
34c2c66affSColin Finck 
_DoDeleteDataObject(IDataObject * pda,DWORD fMask)35c2c66affSColin Finck         static HRESULT _DoDeleteDataObject(IDataObject *pda, DWORD fMask)
36c2c66affSColin Finck         {
37c2c66affSColin Finck             HRESULT hr;
38c2c66affSColin Finck             STGMEDIUM medium;
39c2c66affSColin Finck             FORMATETC formatetc;
40c2c66affSColin Finck             InitFormatEtc (formatetc, CF_HDROP, TYMED_HGLOBAL);
41c2c66affSColin Finck             hr = pda->GetData(&formatetc, &medium);
42c2c66affSColin Finck             if (FAILED_UNEXPECTEDLY(hr))
43c2c66affSColin Finck                 return hr;
44c2c66affSColin Finck 
45c2c66affSColin Finck             LPDROPFILES lpdf = (LPDROPFILES) GlobalLock(medium.hGlobal);
46c2c66affSColin Finck             if (!lpdf)
47c2c66affSColin Finck             {
48c2c66affSColin Finck                 ERR("Error locking global\n");
49bea7848fSWilliam Kent                 ReleaseStgMedium(&medium);
50c2c66affSColin Finck                 return E_FAIL;
51c2c66affSColin Finck             }
52c2c66affSColin Finck 
53c2c66affSColin Finck             /* Delete them */
54c2c66affSColin Finck             SHFILEOPSTRUCTW FileOp;
55c2c66affSColin Finck             ZeroMemory(&FileOp, sizeof(FileOp));
56c2c66affSColin Finck             FileOp.wFunc = FO_DELETE;
57c2c66affSColin Finck             FileOp.pFrom = (LPWSTR) (((byte*) lpdf) + lpdf->pFiles);;
58c2c66affSColin Finck             if ((fMask & CMIC_MASK_SHIFT_DOWN) == 0)
59c2c66affSColin Finck                 FileOp.fFlags = FOF_ALLOWUNDO;
60aab8cd81SKyle Katarn             TRACE("Deleting file (just the first) = %s, allowundo: %d\n", debugstr_w(FileOp.pFrom), (FileOp.fFlags == FOF_ALLOWUNDO));
61c2c66affSColin Finck 
62a5a30fc2SKyle Katarn             int res = SHFileOperationW(&FileOp);
63a5a30fc2SKyle Katarn             if (res)
64c2c66affSColin Finck             {
65a5a30fc2SKyle Katarn                 ERR("SHFileOperation failed with 0x%x\n", res);
66c2c66affSColin Finck                 hr = E_FAIL;
67c2c66affSColin Finck             }
68c2c66affSColin Finck 
69bea7848fSWilliam Kent             GlobalUnlock(medium.hGlobal);
70c2c66affSColin Finck             ReleaseStgMedium(&medium);
71c2c66affSColin Finck 
72c2c66affSColin Finck             return hr;
73c2c66affSColin Finck         }
74c2c66affSColin Finck 
75c2c66affSColin Finck         struct DeleteThreadData {
76c2c66affSColin Finck             IStream *s;
77c2c66affSColin Finck             DWORD fMask;
78c2c66affSColin Finck         };
79c2c66affSColin Finck 
_DoDeleteThreadProc(LPVOID lpParameter)80c2c66affSColin Finck         static DWORD WINAPI _DoDeleteThreadProc(LPVOID lpParameter)
81c2c66affSColin Finck         {
82c2c66affSColin Finck             DeleteThreadData *data = static_cast<DeleteThreadData*>(lpParameter);
83c2c66affSColin Finck             CoInitialize(NULL);
84c2c66affSColin Finck             IDataObject *pDataObject;
85c2c66affSColin Finck             HRESULT hr = CoGetInterfaceAndReleaseStream (data->s, IID_PPV_ARG(IDataObject, &pDataObject));
86c2c66affSColin Finck             if (SUCCEEDED(hr))
87c2c66affSColin Finck             {
88c2c66affSColin Finck                 _DoDeleteDataObject(pDataObject, data->fMask);
89c2c66affSColin Finck             }
90c2c66affSColin Finck             pDataObject->Release();
91c2c66affSColin Finck             CoUninitialize();
92c2c66affSColin Finck             HeapFree(GetProcessHeap(), 0, data);
93c2c66affSColin Finck             return 0;
94c2c66affSColin Finck         }
95c2c66affSColin Finck 
_DoDeleteAsync(IDataObject * pda,DWORD fMask)96c2c66affSColin Finck         static void _DoDeleteAsync(IDataObject *pda, DWORD fMask)
97c2c66affSColin Finck         {
98c2c66affSColin Finck             DeleteThreadData *data = static_cast<DeleteThreadData*>(HeapAlloc(GetProcessHeap(), 0, sizeof(DeleteThreadData)));
99c2c66affSColin Finck             data->fMask = fMask;
100c2c66affSColin Finck             CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pda, &data->s);
101c2c66affSColin Finck             SHCreateThread(_DoDeleteThreadProc, data, NULL, NULL);
102c2c66affSColin Finck         }
103c2c66affSColin Finck 
104c2c66affSColin Finck     public:
CRecyclerDropTarget()105c2c66affSColin Finck         CRecyclerDropTarget()
106c2c66affSColin Finck         {
107c2c66affSColin Finck             fAcceptFmt = FALSE;
108c2c66affSColin Finck             cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
109c2c66affSColin Finck         }
110c2c66affSColin Finck 
111*49b2b1daSKatayama Hirofumi MZ         STDMETHODIMP
DragEnter(IDataObject * pDataObject,DWORD dwKeyState,POINTL pt,DWORD * pdwEffect)112*49b2b1daSKatayama Hirofumi MZ         DragEnter(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect) override
113c2c66affSColin Finck         {
114c2c66affSColin Finck             TRACE("Recycle bin drag over (%p)\n", this);
115c2c66affSColin Finck             /* The recycle bin accepts pretty much everything, and sets a CSIDL flag. */
116c2c66affSColin Finck             fAcceptFmt = TRUE;
117c2c66affSColin Finck 
118c2c66affSColin Finck             *pdwEffect = DROPEFFECT_MOVE;
119c2c66affSColin Finck             return S_OK;
120c2c66affSColin Finck         }
121c2c66affSColin Finck 
122*49b2b1daSKatayama Hirofumi MZ         STDMETHODIMP
DragOver(DWORD dwKeyState,POINTL pt,DWORD * pdwEffect)123*49b2b1daSKatayama Hirofumi MZ         DragOver(DWORD dwKeyState, POINTL pt, DWORD *pdwEffect) override
124c2c66affSColin Finck         {
125c2c66affSColin Finck             TRACE("(%p)\n", this);
126c2c66affSColin Finck 
127c2c66affSColin Finck             if (!pdwEffect)
128c2c66affSColin Finck                 return E_INVALIDARG;
129c2c66affSColin Finck 
130c2c66affSColin Finck             *pdwEffect = DROPEFFECT_MOVE;
131c2c66affSColin Finck 
132c2c66affSColin Finck             return S_OK;
133c2c66affSColin Finck         }
134c2c66affSColin Finck 
135*49b2b1daSKatayama Hirofumi MZ         STDMETHODIMP
DragLeave()136*49b2b1daSKatayama Hirofumi MZ         DragLeave() override
137c2c66affSColin Finck         {
138c2c66affSColin Finck             TRACE("(%p)\n", this);
139c2c66affSColin Finck 
140c2c66affSColin Finck             fAcceptFmt = FALSE;
141c2c66affSColin Finck 
142c2c66affSColin Finck             return S_OK;
143c2c66affSColin Finck         }
144c2c66affSColin Finck 
145*49b2b1daSKatayama Hirofumi MZ         STDMETHODIMP
Drop(IDataObject * pDataObject,DWORD grfKeyState,POINTL pt,DWORD * pdwEffect)146*49b2b1daSKatayama Hirofumi MZ         Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) override
147c2c66affSColin Finck         {
148c2c66affSColin Finck             TRACE("(%p) object dropped on recycle bin, effect %u\n", this, *pdwEffect);
149c2c66affSColin Finck 
150c2c66affSColin Finck             FORMATETC fmt;
151c2c66affSColin Finck             TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
152c2c66affSColin Finck             InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
153c2c66affSColin Finck 
154e217e926SJoachim Henze             /* Handle cfShellIDList Drop objects here, otherwise send the appropriate message to other software */
155c2c66affSColin Finck             if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
156c2c66affSColin Finck             {
157c2c66affSColin Finck                 DWORD fMask = 0;
158c2c66affSColin Finck 
159cc0e2a36SDoug Lyons                 if ((grfKeyState & MK_SHIFT) == MK_SHIFT)
160c2c66affSColin Finck                     fMask |= CMIC_MASK_SHIFT_DOWN;
161c2c66affSColin Finck 
162c2c66affSColin Finck                 _DoDeleteAsync(pDataObject, fMask);
163c2c66affSColin Finck             }
164c2c66affSColin Finck             else
165c2c66affSColin Finck             {
166c2c66affSColin Finck                 /*
167c2c66affSColin Finck                  * TODO call SetData on the data object with format CFSTR_TARGETCLSID
168c2c66affSColin Finck                  * set to the Recycle Bin's class identifier CLSID_RecycleBin.
169c2c66affSColin Finck                  */
170c2c66affSColin Finck             }
171c2c66affSColin Finck             return S_OK;
172c2c66affSColin Finck         }
173c2c66affSColin Finck 
174c2c66affSColin Finck         DECLARE_NOT_AGGREGATABLE(CRecyclerDropTarget)
175c2c66affSColin Finck 
176c2c66affSColin Finck         DECLARE_PROTECT_FINAL_CONSTRUCT()
177c2c66affSColin Finck 
178c2c66affSColin Finck         BEGIN_COM_MAP(CRecyclerDropTarget)
179c2c66affSColin Finck         COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
180c2c66affSColin Finck         END_COM_MAP()
181c2c66affSColin Finck };
182c2c66affSColin Finck 
CRecyclerDropTarget_CreateInstance(REFIID riid,LPVOID * ppvOut)183c2c66affSColin Finck HRESULT CRecyclerDropTarget_CreateInstance(REFIID riid, LPVOID * ppvOut)
184c2c66affSColin Finck {
185c2c66affSColin Finck     return ShellObjectCreator<CRecyclerDropTarget>(riid, ppvOut);
186c2c66affSColin Finck }
187