[SHELL32]
[reactos.git] / dll / win32 / shell32 / dataobject.cpp
1 /*
2 * IEnumFORMATETC, IDataObject
3 *
4 * selecting and droping objects within the shell and/or common dialogs
5 *
6 * Copyright 1998, 1999 <juergen.schmied@metronet.de>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include "precomp.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(shell);
26
27 /***********************************************************************
28 * IEnumFORMATETC implementation
29 */
30
31 class IEnumFORMATETCImpl :
32 public CComObjectRootEx<CComMultiThreadModelNoCS>,
33 public IEnumFORMATETC
34 {
35 private:
36 UINT posFmt;
37 UINT countFmt;
38 LPFORMATETC pFmt;
39 public:
40 IEnumFORMATETCImpl();
41 ~IEnumFORMATETCImpl();
42 HRESULT WINAPI Initialize(UINT cfmt, const FORMATETC afmt[]);
43
44 // *****************
45 virtual HRESULT WINAPI Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed);
46 virtual HRESULT WINAPI Skip(ULONG celt);
47 virtual HRESULT WINAPI Reset();
48 virtual HRESULT WINAPI Clone(LPENUMFORMATETC* ppenum);
49
50 BEGIN_COM_MAP(IEnumFORMATETCImpl)
51 COM_INTERFACE_ENTRY_IID(IID_IEnumFORMATETC, IEnumFORMATETC)
52 END_COM_MAP()
53 };
54
55 IEnumFORMATETCImpl::IEnumFORMATETCImpl()
56 {
57 posFmt = 0;
58 countFmt = 0;
59 pFmt = NULL;
60 }
61
62 IEnumFORMATETCImpl::~IEnumFORMATETCImpl()
63 {
64 }
65
66 HRESULT WINAPI IEnumFORMATETCImpl::Initialize(UINT cfmt, const FORMATETC afmt[])
67 {
68 DWORD size;
69
70 size = cfmt * sizeof(FORMATETC);
71 countFmt = cfmt;
72 pFmt = (LPFORMATETC)SHAlloc(size);
73 if (pFmt == NULL)
74 return E_OUTOFMEMORY;
75
76 memcpy(pFmt, afmt, size);
77 return S_OK;
78 }
79
80 HRESULT WINAPI IEnumFORMATETCImpl::Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
81 {
82 UINT i;
83
84 TRACE("(%p)->(%u,%p)\n", this, celt, rgelt);
85
86 if(!pFmt)return S_FALSE;
87 if(!rgelt) return E_INVALIDARG;
88 if (pceltFethed) *pceltFethed = 0;
89
90 for(i = 0; posFmt < countFmt && celt > i; i++)
91 {
92 *rgelt++ = pFmt[posFmt++];
93 }
94
95 if (pceltFethed) *pceltFethed = i;
96
97 return ((i == celt) ? S_OK : S_FALSE);
98 }
99
100 HRESULT WINAPI IEnumFORMATETCImpl::Skip(ULONG celt)
101 {
102 TRACE("(%p)->(num=%u)\n", this, celt);
103
104 if (posFmt + celt >= countFmt) return S_FALSE;
105 posFmt += celt;
106 return S_OK;
107 }
108
109 HRESULT WINAPI IEnumFORMATETCImpl::Reset()
110 {
111 TRACE("(%p)->()\n", this);
112
113 posFmt = 0;
114 return S_OK;
115 }
116
117 HRESULT WINAPI IEnumFORMATETCImpl::Clone(LPENUMFORMATETC* ppenum)
118 {
119 HRESULT hResult;
120
121 TRACE("(%p)->(ppenum=%p)\n", this, ppenum);
122
123 if (!ppenum) return E_INVALIDARG;
124 hResult = IEnumFORMATETC_Constructor(countFmt, pFmt, ppenum);
125 if (FAILED (hResult))
126 return hResult;
127 return (*ppenum)->Skip(posFmt);
128 }
129
130 HRESULT IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[], IEnumFORMATETC **ppFormat)
131 {
132 return ShellObjectCreatorInit<IEnumFORMATETCImpl>(cfmt, afmt, IID_IEnumFORMATETC, ppFormat);
133 }
134
135
136 /***********************************************************************
137 * IDataObject implementation
138 */
139
140 /* number of supported formats */
141 #define MAX_FORMATS 5
142
143 class IDataObjectImpl :
144 public CComObjectRootEx<CComMultiThreadModelNoCS>,
145 public IDataObject,
146 public IAsyncOperation
147 {
148 private:
149 LPITEMIDLIST pidl;
150 LPITEMIDLIST * apidl;
151 UINT cidl;
152 DWORD dropeffect;
153
154 FORMATETC pFormatEtc[MAX_FORMATS];
155 UINT cfShellIDList;
156 UINT cfFileNameA;
157 UINT cfFileNameW;
158 UINT cfPreferredDropEffect;
159 BOOL doasync;
160 public:
161 IDataObjectImpl();
162 ~IDataObjectImpl();
163 HRESULT WINAPI Initialize(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidlx, UINT cidlx);
164
165 ///////////
166 virtual HRESULT WINAPI GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium);
167 virtual HRESULT WINAPI GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium);
168 virtual HRESULT WINAPI QueryGetData(LPFORMATETC pformatetc);
169 virtual HRESULT WINAPI GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut);
170 virtual HRESULT WINAPI SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease);
171 virtual HRESULT WINAPI EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc);
172 virtual HRESULT WINAPI DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
173 virtual HRESULT WINAPI DUnadvise(DWORD dwConnection);
174 virtual HRESULT WINAPI EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
175 virtual HRESULT WINAPI GetAsyncMode(BOOL *pfIsOpAsync);
176 virtual HRESULT WINAPI InOperation(BOOL *pfInAsyncOp);
177 virtual HRESULT WINAPI SetAsyncMode(BOOL fDoOpAsync);
178 virtual HRESULT WINAPI StartOperation(IBindCtx *pbcReserved);
179 virtual HRESULT WINAPI EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects);
180
181 BEGIN_COM_MAP(IDataObjectImpl)
182 COM_INTERFACE_ENTRY_IID(IID_IDataObject, IDataObject)
183 COM_INTERFACE_ENTRY_IID(IID_IAsyncOperation, IAsyncOperation)
184 END_COM_MAP()
185 };
186
187 IDataObjectImpl::IDataObjectImpl()
188 {
189 pidl = NULL;
190 apidl = NULL;
191 cidl = 0;
192 dropeffect = 0;
193 cfShellIDList = 0;
194 cfFileNameA = 0;
195 cfFileNameW = 0;
196 cfPreferredDropEffect = 0;
197 doasync = FALSE;
198 }
199
200 IDataObjectImpl::~IDataObjectImpl()
201 {
202 TRACE(" destroying IDataObject(%p)\n",this);
203 _ILFreeaPidl(apidl, cidl);
204 ILFree(pidl);
205 }
206
207 HRESULT WINAPI IDataObjectImpl::Initialize(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidlx, UINT cidlx)
208 {
209 pidl = ILClone(pMyPidl);
210 apidl = _ILCopyaPidl(apidlx, cidlx);
211 if (pidl == NULL || apidl == NULL)
212 return E_OUTOFMEMORY;
213 cidl = cidlx;
214 dropeffect = DROPEFFECT_COPY;
215
216 cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
217 cfFileNameA = RegisterClipboardFormatA(CFSTR_FILENAMEA);
218 cfFileNameW = RegisterClipboardFormatW(CFSTR_FILENAMEW);
219 cfPreferredDropEffect = RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECTW);
220 InitFormatEtc(pFormatEtc[0], cfShellIDList, TYMED_HGLOBAL);
221 InitFormatEtc(pFormatEtc[1], CF_HDROP, TYMED_HGLOBAL);
222 InitFormatEtc(pFormatEtc[2], cfFileNameA, TYMED_HGLOBAL);
223 InitFormatEtc(pFormatEtc[3], cfFileNameW, TYMED_HGLOBAL);
224 InitFormatEtc(pFormatEtc[4], cfPreferredDropEffect, TYMED_HGLOBAL);
225 return S_OK;
226 }
227
228 /**************************************************************************
229 * IDataObject_fnGetData
230 */
231 HRESULT WINAPI IDataObjectImpl::GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium)
232 {
233 char szTemp[256];
234
235 szTemp[0] = 0;
236 GetClipboardFormatNameA (pformatetcIn->cfFormat, szTemp, 256);
237 TRACE("(%p)->(%p %p format=%s)\n", this, pformatetcIn, pmedium, szTemp);
238
239 if (pformatetcIn->cfFormat == cfShellIDList)
240 {
241 if (cidl < 1) return(E_UNEXPECTED);
242 pmedium->hGlobal = RenderSHELLIDLIST(pidl, apidl, cidl);
243 }
244 else if (pformatetcIn->cfFormat == CF_HDROP)
245 {
246 if (cidl < 1) return(E_UNEXPECTED);
247 pmedium->hGlobal = RenderHDROP(pidl, apidl, cidl);
248 }
249 else if (pformatetcIn->cfFormat == cfFileNameA)
250 {
251 if (cidl < 1) return(E_UNEXPECTED);
252 pmedium->hGlobal = RenderFILENAMEA(pidl, apidl, cidl);
253 }
254 else if (pformatetcIn->cfFormat == cfFileNameW)
255 {
256 if (cidl < 1) return(E_UNEXPECTED);
257 pmedium->hGlobal = RenderFILENAMEW(pidl, apidl, cidl);
258 }
259 else if (pformatetcIn->cfFormat == cfPreferredDropEffect)
260 {
261 pmedium->hGlobal = RenderPREFEREDDROPEFFECT(dropeffect);
262 }
263 else
264 {
265 FIXME("-- expected clipformat not implemented\n");
266 return (E_INVALIDARG);
267 }
268 if (pmedium->hGlobal)
269 {
270 pmedium->tymed = TYMED_HGLOBAL;
271 pmedium->pUnkForRelease = NULL;
272 return S_OK;
273 }
274 return E_OUTOFMEMORY;
275 }
276
277 HRESULT WINAPI IDataObjectImpl::GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium)
278 {
279 FIXME("(%p)->()\n", this);
280 return E_NOTIMPL;
281 }
282
283 HRESULT WINAPI IDataObjectImpl::QueryGetData(LPFORMATETC pformatetc)
284 {
285 UINT i;
286
287 TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", this, pformatetc->cfFormat, pformatetc->tymed);
288
289 if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
290 return DV_E_DVASPECT;
291
292 /* check our formats table what we have */
293 for (i=0; i<MAX_FORMATS; i++)
294 {
295 if ((pFormatEtc[i].cfFormat == pformatetc->cfFormat)
296 && (pFormatEtc[i].tymed == pformatetc->tymed))
297 {
298 return S_OK;
299 }
300 }
301
302 return DV_E_TYMED;
303 }
304
305 HRESULT WINAPI IDataObjectImpl::GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut)
306 {
307 FIXME("(%p)->()\n", this);
308 return E_NOTIMPL;
309 }
310
311 HRESULT WINAPI IDataObjectImpl::SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
312 {
313 if (pformatetc->cfFormat == cfPreferredDropEffect)
314 {
315 const DWORD *src = (const DWORD *)GlobalLock(pmedium->hGlobal);
316 if (src != 0)
317 {
318 dropeffect = *src;
319 GlobalUnlock(pmedium->hGlobal);
320 return S_OK;
321 }
322 FIXME("Error setting data");
323 return E_FAIL;
324 }
325
326 FIXME("(%p)->()\n", this);
327 return E_NOTIMPL;
328 }
329
330 HRESULT WINAPI IDataObjectImpl::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
331 {
332 TRACE("(%p)->()\n", this);
333 *ppenumFormatEtc = NULL;
334
335 /* only get data */
336 if (DATADIR_GET == dwDirection)
337 {
338 return IEnumFORMATETC_Constructor(MAX_FORMATS, pFormatEtc, ppenumFormatEtc);
339 }
340
341 return E_NOTIMPL;
342 }
343
344 HRESULT WINAPI IDataObjectImpl::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
345 {
346 FIXME("(%p)->()\n", this);
347 return E_NOTIMPL;
348 }
349
350 HRESULT WINAPI IDataObjectImpl::DUnadvise(DWORD dwConnection)
351 {
352 FIXME("(%p)->()\n", this);
353 return E_NOTIMPL;
354 }
355
356 HRESULT WINAPI IDataObjectImpl::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
357 {
358 FIXME("(%p)->()\n", this);
359 return E_NOTIMPL;
360 }
361
362 HRESULT WINAPI IDataObjectImpl::GetAsyncMode(BOOL *pfIsOpAsync)
363 {
364 TRACE("(%p)->()\n", this);
365 *pfIsOpAsync = doasync;
366 return S_OK;
367 }
368 HRESULT WINAPI IDataObjectImpl::InOperation(BOOL *pfInAsyncOp)
369 {
370 FIXME("(%p)->()\n", this);
371 return E_NOTIMPL;
372 }
373 HRESULT WINAPI IDataObjectImpl::SetAsyncMode(BOOL fDoOpAsync)
374 {
375 TRACE("(%p)->()\n", this);
376 doasync = fDoOpAsync;
377 return S_OK;
378 }
379
380 HRESULT WINAPI IDataObjectImpl::StartOperation(IBindCtx *pbcReserved)
381 {
382 FIXME("(%p)->()\n", this);
383 return E_NOTIMPL;
384 }
385 HRESULT WINAPI IDataObjectImpl::EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects)
386 {
387 FIXME("(%p)->()\n", this);
388 return E_NOTIMPL;
389 }
390
391
392
393 /**************************************************************************
394 * IDataObject_Constructor
395 */
396 HRESULT IDataObject_Constructor(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidl, UINT cidl, IDataObject **dataObject)
397 {
398 return ShellObjectCreatorInit<IDataObjectImpl>(hwndOwner, pMyPidl, apidl, cidl, IID_IDataObject, dataObject);
399 }
400
401 /*************************************************************************
402 * SHCreateDataObject [SHELL32.@]
403 *
404 */
405
406 HRESULT WINAPI SHCreateDataObject(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST* apidl, IDataObject *pdtInner, REFIID riid, void **ppv)
407 {
408 if (IsEqualIID(riid, IID_IDataObject))
409 {
410 return CIDLData_CreateFromIDArray(pidlFolder, cidl, apidl, (IDataObject **)ppv);
411 }
412 return E_FAIL;
413 }