[LT2013]
[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 **enumerator)
131 {
132 CComObject<IEnumFORMATETCImpl> *theEnumerator;
133 CComPtr<IEnumFORMATETC> result;
134 HRESULT hResult;
135
136 if (enumerator == NULL)
137 return E_POINTER;
138 *enumerator = NULL;
139 ATLTRY (theEnumerator = new CComObject<IEnumFORMATETCImpl>);
140 if (theEnumerator == NULL)
141 return E_OUTOFMEMORY;
142 hResult = theEnumerator->QueryInterface (IID_IEnumFORMATETC, (void **)&result);
143 if (FAILED (hResult))
144 {
145 delete theEnumerator;
146 return hResult;
147 }
148 hResult = theEnumerator->Initialize (cfmt, afmt);
149 if (FAILED (hResult))
150 return hResult;
151 *enumerator = result.Detach ();
152 TRACE("(%p)->(%u,%p)\n", *enumerator, cfmt, afmt);
153 return S_OK;
154 }
155
156
157 /***********************************************************************
158 * IDataObject implementation
159 */
160
161 /* number of supported formats */
162 #define MAX_FORMATS 4
163
164 class IDataObjectImpl :
165 public CComObjectRootEx<CComMultiThreadModelNoCS>,
166 public IDataObject
167 {
168 private:
169 LPITEMIDLIST pidl;
170 LPITEMIDLIST * apidl;
171 UINT cidl;
172
173 FORMATETC pFormatEtc[MAX_FORMATS];
174 UINT cfShellIDList;
175 UINT cfFileNameA;
176 UINT cfFileNameW;
177 public:
178 IDataObjectImpl();
179 ~IDataObjectImpl();
180 HRESULT WINAPI Initialize(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidlx, UINT cidlx);
181
182 ///////////
183 virtual HRESULT WINAPI GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium);
184 virtual HRESULT WINAPI GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium);
185 virtual HRESULT WINAPI QueryGetData(LPFORMATETC pformatetc);
186 virtual HRESULT WINAPI GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut);
187 virtual HRESULT WINAPI SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease);
188 virtual HRESULT WINAPI EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc);
189 virtual HRESULT WINAPI DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
190 virtual HRESULT WINAPI DUnadvise(DWORD dwConnection);
191 virtual HRESULT WINAPI EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
192
193 BEGIN_COM_MAP(IDataObjectImpl)
194 COM_INTERFACE_ENTRY_IID(IID_IDataObject, IDataObject)
195 END_COM_MAP()
196 };
197
198 IDataObjectImpl::IDataObjectImpl()
199 {
200 pidl = NULL;
201 apidl = NULL;
202 cidl = 0;
203 cfShellIDList = 0;
204 cfFileNameA = 0;
205 cfFileNameW = 0;
206 }
207
208 IDataObjectImpl::~IDataObjectImpl()
209 {
210 TRACE(" destroying IDataObject(%p)\n",this);
211 _ILFreeaPidl(apidl, cidl);
212 ILFree(pidl);
213 }
214
215 HRESULT WINAPI IDataObjectImpl::Initialize(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidlx, UINT cidlx)
216 {
217 pidl = ILClone(pMyPidl);
218 apidl = _ILCopyaPidl(apidlx, cidlx);
219 if (pidl == NULL || apidl == NULL)
220 return E_OUTOFMEMORY;
221 cidl = cidlx;
222
223 cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
224 cfFileNameA = RegisterClipboardFormatA(CFSTR_FILENAMEA);
225 cfFileNameW = RegisterClipboardFormatW(CFSTR_FILENAMEW);
226 InitFormatEtc(pFormatEtc[0], cfShellIDList, TYMED_HGLOBAL);
227 InitFormatEtc(pFormatEtc[1], CF_HDROP, TYMED_HGLOBAL);
228 InitFormatEtc(pFormatEtc[2], cfFileNameA, TYMED_HGLOBAL);
229 InitFormatEtc(pFormatEtc[3], cfFileNameW, TYMED_HGLOBAL);
230 return S_OK;
231 }
232
233 /**************************************************************************
234 * IDataObject_fnGetData
235 */
236 HRESULT WINAPI IDataObjectImpl::GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium)
237 {
238 char szTemp[256];
239
240 szTemp[0] = 0;
241 GetClipboardFormatNameA (pformatetcIn->cfFormat, szTemp, 256);
242 TRACE("(%p)->(%p %p format=%s)\n", this, pformatetcIn, pmedium, szTemp);
243
244 if (pformatetcIn->cfFormat == cfShellIDList)
245 {
246 if (cidl < 1) return(E_UNEXPECTED);
247 pmedium->hGlobal = RenderSHELLIDLIST(pidl, apidl, cidl);
248 }
249 else if (pformatetcIn->cfFormat == CF_HDROP)
250 {
251 if (cidl < 1) return(E_UNEXPECTED);
252 pmedium->hGlobal = RenderHDROP(pidl, apidl, cidl);
253 }
254 else if (pformatetcIn->cfFormat == cfFileNameA)
255 {
256 if (cidl < 1) return(E_UNEXPECTED);
257 pmedium->hGlobal = RenderFILENAMEA(pidl, apidl, cidl);
258 }
259 else if (pformatetcIn->cfFormat == cfFileNameW)
260 {
261 if (cidl < 1) return(E_UNEXPECTED);
262 pmedium->hGlobal = RenderFILENAMEW(pidl, apidl, cidl);
263 }
264 else
265 {
266 FIXME("-- expected clipformat not implemented\n");
267 return (E_INVALIDARG);
268 }
269 if (pmedium->hGlobal)
270 {
271 pmedium->tymed = TYMED_HGLOBAL;
272 pmedium->pUnkForRelease = NULL;
273 return S_OK;
274 }
275 return E_OUTOFMEMORY;
276 }
277
278 HRESULT WINAPI IDataObjectImpl::GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium)
279 {
280 FIXME("(%p)->()\n", this);
281 return E_NOTIMPL;
282 }
283
284 HRESULT WINAPI IDataObjectImpl::QueryGetData(LPFORMATETC pformatetc)
285 {
286 UINT i;
287
288 TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", this, pformatetc->cfFormat, pformatetc->tymed);
289
290 if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
291 return DV_E_DVASPECT;
292
293 /* check our formats table what we have */
294 for (i=0; i<MAX_FORMATS; i++)
295 {
296 if ((pFormatEtc[i].cfFormat == pformatetc->cfFormat)
297 && (pFormatEtc[i].tymed == pformatetc->tymed))
298 {
299 return S_OK;
300 }
301 }
302
303 return DV_E_TYMED;
304 }
305
306 HRESULT WINAPI IDataObjectImpl::GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut)
307 {
308 FIXME("(%p)->()\n", this);
309 return E_NOTIMPL;
310 }
311
312 HRESULT WINAPI IDataObjectImpl::SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
313 {
314 FIXME("(%p)->()\n", this);
315 return E_NOTIMPL;
316 }
317
318 HRESULT WINAPI IDataObjectImpl::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
319 {
320 TRACE("(%p)->()\n", this);
321 *ppenumFormatEtc = NULL;
322
323 /* only get data */
324 if (DATADIR_GET == dwDirection)
325 {
326 return IEnumFORMATETC_Constructor(MAX_FORMATS, pFormatEtc, ppenumFormatEtc);
327 }
328
329 return E_NOTIMPL;
330 }
331
332 HRESULT WINAPI IDataObjectImpl::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
333 {
334 FIXME("(%p)->()\n", this);
335 return E_NOTIMPL;
336 }
337
338 HRESULT WINAPI IDataObjectImpl::DUnadvise(DWORD dwConnection)
339 {
340 FIXME("(%p)->()\n", this);
341 return E_NOTIMPL;
342 }
343
344 HRESULT WINAPI IDataObjectImpl::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
345 {
346 FIXME("(%p)->()\n", this);
347 return E_NOTIMPL;
348 }
349
350 /**************************************************************************
351 * IDataObject_Constructor
352 */
353 HRESULT IDataObject_Constructor(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidl, UINT cidl, IDataObject **dataObject)
354 {
355 CComObject<IDataObjectImpl> *theDataObject;
356 CComPtr<IDataObject> result;
357 HRESULT hResult;
358
359 if (dataObject == NULL)
360 return E_POINTER;
361 *dataObject = NULL;
362 ATLTRY (theDataObject = new CComObject<IDataObjectImpl>);
363 if (theDataObject == NULL)
364 return E_OUTOFMEMORY;
365 hResult = theDataObject->QueryInterface (IID_IDataObject, (void **)&result);
366 if (FAILED (hResult))
367 {
368 delete theDataObject;
369 return hResult;
370 }
371 hResult = theDataObject->Initialize (hwndOwner, pMyPidl, apidl, cidl);
372 if (FAILED (hResult))
373 return hResult;
374 *dataObject = result.Detach ();
375 TRACE("(%p)->(apidl=%p cidl=%u)\n", *dataObject, apidl, cidl);
376 return S_OK;
377 }
378
379 /*************************************************************************
380 * SHCreateDataObject [SHELL32.@]
381 *
382 */
383
384 HRESULT WINAPI SHCreateDataObject(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST* apidl, IDataObject *pdtInner, REFIID riid, void **ppv)
385 {
386 if (IsEqualIID(riid, IID_IDataObject))
387 {
388 return CIDLData_CreateFromIDArray(pidlFolder, cidl, apidl, (IDataObject **)ppv);
389 }
390 return E_FAIL;
391 }