* Sync up to trunk head (r65481).
[reactos.git] / base / shell / explorer / dragdrop.cpp
1 /*
2 * ReactOS Explorer
3 *
4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "precomp.h"
22
23 class CDropTarget :
24 public CComCoClass<CDropTarget>,
25 public CComObjectRootEx<CComMultiThreadModelNoCS>,
26 public IDropTarget
27 {
28 HWND hwndTarget;
29 CComPtr<IDropTargetHelper> DropTargetHelper;
30 PVOID Context;
31 BOOL CanDrop;
32 DROPTARGET_CALLBACKS Callbacks;
33 DWORD FormatsCount;
34 FORMATETC* Formats;
35
36 const FORMATETC *
37 FindSupportedFormat(IN IDataObject *pDataObject)
38 {
39 FORMATETC *Current, *Last;
40 HRESULT hr;
41
42 /* NOTE: we could use IDataObject::EnumFormatEtc(),
43 but this appears to be a lot easier! */
44 Last = Formats + FormatsCount;
45 for (Current = Formats;
46 Current != Last;
47 Current++)
48 {
49 hr = pDataObject->QueryGetData(Current);
50 if (SUCCEEDED(hr))
51 return Current;
52 }
53
54 return NULL;
55 }
56
57 public:
58 CDropTarget() :
59 hwndTarget(NULL),
60 Context(NULL),
61 CanDrop(FALSE),
62 FormatsCount(0),
63 Formats(NULL)
64 {
65 ZeroMemory(&Callbacks, sizeof(Callbacks));
66 }
67
68 virtual ~CDropTarget() { }
69
70 HRESULT Initialize(IN HWND hwndTarget,
71 IN DWORD nSupportedFormats,
72 IN const FORMATETC *formats OPTIONAL,
73 IN PVOID Context OPTIONAL,
74 IN const DROPTARGET_CALLBACKS *Callbacks OPTIONAL)
75 {
76 this->hwndTarget = hwndTarget;
77 FormatsCount = nSupportedFormats;
78 if (nSupportedFormats != 0)
79 {
80 Formats = new FORMATETC[nSupportedFormats];
81 CopyMemory(Formats,
82 formats,
83 sizeof(formats[0]) * nSupportedFormats);
84 }
85
86 this->Context = Context;
87 if (Callbacks != NULL)
88 {
89 CopyMemory(&this->Callbacks,
90 Callbacks,
91 sizeof(*Callbacks));
92 }
93
94 HRESULT hr = CoCreateInstance(CLSID_DragDropHelper,
95 NULL,
96 CLSCTX_INPROC_SERVER,
97 IID_PPV_ARG(IDropTargetHelper, &DropTargetHelper));
98
99 return hr;
100 }
101
102 virtual HRESULT STDMETHODCALLTYPE DragEnter(
103 IN IDataObject *pDataObject,
104 IN DWORD grfKeyState,
105 IN POINTL pt,
106 IN OUT DWORD *pdwEffect)
107 {
108 const FORMATETC *Format;
109 HRESULT hr;
110
111 if (pDataObject == NULL)
112 return E_INVALIDARG;
113
114 CanDrop = FALSE;
115
116 hr = DropTargetHelper->DragEnter(
117 hwndTarget,
118 pDataObject,
119 (POINT *) &pt,
120 *pdwEffect);
121
122 if (SUCCEEDED(hr))
123 {
124 Format = FindSupportedFormat(
125 pDataObject);
126 if (Format != NULL)
127 {
128 /* We found a format that we support! */
129 if (Callbacks.OnDragEnter != NULL)
130 {
131 hr = Callbacks.OnDragEnter(this,
132 Context,
133 Format,
134 grfKeyState,
135 pt,
136 pdwEffect);
137 if (SUCCEEDED(hr))
138 {
139 if (hr == S_OK)
140 CanDrop = TRUE;
141 else
142 {
143 /* Special return value by the callback routine,
144 doesn't want to allow dragging */
145 *pdwEffect = DROPEFFECT_NONE;
146 }
147
148 hr = S_OK;
149 }
150 else
151 {
152 *pdwEffect = DROPEFFECT_NONE;
153 hr = S_OK;
154 }
155 }
156 else
157 *pdwEffect = DROPEFFECT_NONE;
158 }
159 else
160 *pdwEffect = DROPEFFECT_NONE;
161 }
162
163 return hr;
164 }
165
166 virtual HRESULT STDMETHODCALLTYPE DragOver(
167 IN DWORD grfKeyState,
168 IN POINTL pt,
169 IN OUT DWORD *pdwEffect)
170 {
171 HRESULT hr;
172
173 hr = DropTargetHelper->DragOver(
174 (POINT *) &pt,
175 *pdwEffect);
176
177 if (SUCCEEDED(hr))
178 {
179 if (CanDrop)
180 {
181 if (Callbacks.OnDragOver != NULL)
182 {
183 hr = Callbacks.OnDragOver(this,
184 Context,
185 grfKeyState,
186 pt,
187 pdwEffect);
188 if (SUCCEEDED(hr))
189 {
190 if (hr != S_OK)
191 {
192 /* Special return value by the callback routine,
193 doesn't want to allow dropping here */
194 *pdwEffect = DROPEFFECT_NONE;
195 }
196
197 hr = S_OK;
198 }
199 else
200 {
201 *pdwEffect = DROPEFFECT_NONE;
202 hr = S_OK;
203 }
204 }
205 else
206 *pdwEffect = DROPEFFECT_NONE;
207 }
208 else
209 *pdwEffect = DROPEFFECT_NONE;
210 }
211
212 return hr;
213 }
214
215 virtual HRESULT STDMETHODCALLTYPE DragLeave()
216 {
217 HRESULT hr;
218
219 hr = DropTargetHelper->DragLeave();
220 if (SUCCEEDED(hr))
221 {
222 if (Callbacks.OnDragLeave != NULL)
223 {
224 hr = Callbacks.OnDragLeave(this,
225 Context);
226 }
227 }
228
229 return hr;
230 }
231
232 virtual HRESULT STDMETHODCALLTYPE Drop(
233 IN IDataObject *pDataObject,
234 IN DWORD grfKeyState,
235 IN POINTL pt,
236 IN OUT DWORD *pdwEffect)
237 {
238 const FORMATETC *Format;
239 HRESULT hr;
240
241 if (pDataObject == NULL)
242 return E_INVALIDARG;
243
244 hr = DropTargetHelper->Drop(
245 pDataObject,
246 (POINT *) &pt,
247 *pdwEffect);
248
249 if (SUCCEEDED(hr) && CanDrop)
250 {
251 Format = FindSupportedFormat(pDataObject);
252 if (Format != NULL)
253 {
254 /* We found a format that we support! */
255 if (Callbacks.OnDrop != NULL)
256 {
257 hr = Callbacks.OnDrop(this,
258 Context,
259 Format,
260 grfKeyState,
261 pt,
262 pdwEffect);
263 if (SUCCEEDED(hr))
264 {
265 if (hr == S_OK)
266 CanDrop = TRUE;
267 else
268 {
269 /* Special return value by the callback routine,
270 doesn't want to allow dragging */
271 *pdwEffect = DROPEFFECT_NONE;
272 }
273
274 hr = S_OK;
275 }
276 else
277 {
278 *pdwEffect = DROPEFFECT_NONE;
279 hr = S_OK;
280 }
281 }
282 else
283 *pdwEffect = DROPEFFECT_NONE;
284 }
285 else
286 *pdwEffect = DROPEFFECT_NONE;
287 }
288
289 return hr;
290 }
291
292 DECLARE_NOT_AGGREGATABLE(CDropTarget)
293
294 DECLARE_PROTECT_FINAL_CONSTRUCT()
295 BEGIN_COM_MAP(CDropTarget)
296 COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
297 END_COM_MAP()
298 };
299
300 IDropTarget *
301 CreateDropTarget(IN HWND hwndTarget,
302 IN DWORD nSupportedFormats,
303 IN const FORMATETC *Formats OPTIONAL,
304 IN PVOID Context OPTIONAL,
305 IN const DROPTARGET_CALLBACKS *Callbacks OPTIONAL)
306 {
307 IDropTarget *dt;
308
309 HRESULT hr = ShellObjectCreatorInit<CDropTarget>(hwndTarget, nSupportedFormats, Formats, Context, Callbacks, IID_IDropTarget, &dt);
310 if (FAILED_UNEXPECTEDLY(hr))
311 return NULL;
312
313 return dt;
314 }