xref: /reactos/dll/win32/shell32/CIDLDataObj.cpp (revision ae2a85d0)
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_PPV_ARG(IEnumFORMATETC, ppFormat));
133 }
134 
135 
136 /***********************************************************************
137 *   IDataObject implementation
138 */
139 
140 /* number of supported formats */
141 #define MAX_FORMATS 5
142 
143 class CIDLDataObj :
144     public CComObjectRootEx<CComMultiThreadModelNoCS>,
145     public IDataObject,
146     public IAsyncOperation
147 {
148 private:
149     LPITEMIDLIST    pidl;
150     PIDLIST_RELATIVE *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     CIDLDataObj();
162     ~CIDLDataObj();
163     HRESULT WINAPI Initialize(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl, PCUIDLIST_RELATIVE_ARRAY 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(CIDLDataObj)
182     COM_INTERFACE_ENTRY_IID(IID_IDataObject, IDataObject)
183     COM_INTERFACE_ENTRY_IID(IID_IAsyncOperation,  IAsyncOperation)
184 END_COM_MAP()
185 };
186 
187 CIDLDataObj::CIDLDataObj()
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 CIDLDataObj::~CIDLDataObj()
201 {
202     TRACE(" destroying IDataObject(%p)\n",this);
203     _ILFreeaPidl(apidl, cidl);
204     ILFree(pidl);
205 }
206 
207 HRESULT WINAPI CIDLDataObj::Initialize(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl, PCUIDLIST_RELATIVE_ARRAY 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 static HGLOBAL RenderPREFEREDDROPEFFECT (DWORD dwFlags)
229 {
230     DWORD * pdwFlag;
231     HGLOBAL hGlobal;
232 
233     TRACE("(0x%08x)\n", dwFlags);
234 
235     hGlobal = GlobalAlloc(GHND|GMEM_SHARE, sizeof(DWORD));
236     if(!hGlobal) return hGlobal;
237         pdwFlag = (DWORD*)GlobalLock(hGlobal);
238     *pdwFlag = dwFlags;
239     GlobalUnlock(hGlobal);
240     return hGlobal;
241 }
242 
243 /**************************************************************************
244 * IDataObject_fnGetData
245 */
246 HRESULT WINAPI CIDLDataObj::GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium)
247 {
248     char    szTemp[256];
249 
250     szTemp[0] = 0;
251     GetClipboardFormatNameA (pformatetcIn->cfFormat, szTemp, 256);
252     TRACE("(%p)->(%p %p format=%s)\n", this, pformatetcIn, pmedium, szTemp);
253 
254     if (pformatetcIn->cfFormat == cfShellIDList)
255     {
256       if (cidl < 1) return(E_UNEXPECTED);
257       pmedium->hGlobal = RenderSHELLIDLIST(pidl, apidl, cidl);
258     }
259     else if    (pformatetcIn->cfFormat == CF_HDROP)
260     {
261       if (cidl < 1) return(E_UNEXPECTED);
262       pmedium->hGlobal = RenderHDROP(pidl, apidl, cidl);
263     }
264     else if    (pformatetcIn->cfFormat == cfFileNameA)
265     {
266       if (cidl < 1) return(E_UNEXPECTED);
267       pmedium->hGlobal = RenderFILENAMEA(pidl, apidl, cidl);
268     }
269     else if    (pformatetcIn->cfFormat == cfFileNameW)
270     {
271       if (cidl < 1) return(E_UNEXPECTED);
272       pmedium->hGlobal = RenderFILENAMEW(pidl, apidl, cidl);
273     }
274     else if    (pformatetcIn->cfFormat == cfPreferredDropEffect)
275     {
276       pmedium->hGlobal = RenderPREFEREDDROPEFFECT(dropeffect);
277     }
278     else
279     {
280       FIXME("-- expected clipformat not implemented\n");
281       return (E_INVALIDARG);
282     }
283     if (pmedium->hGlobal)
284     {
285       pmedium->tymed = TYMED_HGLOBAL;
286       pmedium->pUnkForRelease = NULL;
287       return S_OK;
288     }
289     return E_OUTOFMEMORY;
290 }
291 
292 HRESULT WINAPI CIDLDataObj::GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium)
293 {
294     FIXME("(%p)->()\n", this);
295     return E_NOTIMPL;
296 }
297 
298 HRESULT WINAPI CIDLDataObj::QueryGetData(LPFORMATETC pformatetc)
299 {
300     UINT i;
301 
302     TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", this, pformatetc->cfFormat, pformatetc->tymed);
303 
304     if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
305       return DV_E_DVASPECT;
306 
307     /* check our formats table what we have */
308     for (i=0; i<MAX_FORMATS; i++)
309     {
310       if ((pFormatEtc[i].cfFormat == pformatetc->cfFormat)
311        && (pFormatEtc[i].tymed == pformatetc->tymed))
312       {
313         return S_OK;
314       }
315     }
316 
317     return DV_E_TYMED;
318 }
319 
320 HRESULT WINAPI CIDLDataObj::GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut)
321 {
322     FIXME("(%p)->()\n", this);
323     return E_NOTIMPL;
324 }
325 
326 HRESULT WINAPI CIDLDataObj::SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
327 {
328     if (pformatetc->cfFormat == cfPreferredDropEffect)
329     {
330       const DWORD *src = (const DWORD *)GlobalLock(pmedium->hGlobal);
331       if (src != 0)
332       {
333         dropeffect = *src;
334         GlobalUnlock(pmedium->hGlobal);
335         return S_OK;
336       }
337       FIXME("Error setting data");
338       return E_FAIL;
339     }
340 
341     FIXME("(%p)->()\n", this);
342     return E_NOTIMPL;
343 }
344 
345 HRESULT WINAPI CIDLDataObj::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
346 {
347     TRACE("(%p)->()\n", this);
348     *ppenumFormatEtc = NULL;
349 
350     /* only get data */
351     if (DATADIR_GET == dwDirection)
352     {
353         return IEnumFORMATETC_Constructor(MAX_FORMATS, pFormatEtc, ppenumFormatEtc);
354     }
355 
356     return E_NOTIMPL;
357 }
358 
359 HRESULT WINAPI CIDLDataObj::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
360 {
361     FIXME("(%p)->()\n", this);
362     return E_NOTIMPL;
363 }
364 
365 HRESULT WINAPI CIDLDataObj::DUnadvise(DWORD dwConnection)
366 {
367     FIXME("(%p)->()\n", this);
368     return E_NOTIMPL;
369 }
370 
371 HRESULT WINAPI CIDLDataObj::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
372 {
373     FIXME("(%p)->()\n", this);
374     return E_NOTIMPL;
375 }
376 
377 HRESULT WINAPI CIDLDataObj::GetAsyncMode(BOOL *pfIsOpAsync)
378 {
379     TRACE("(%p)->()\n", this);
380     *pfIsOpAsync = doasync;
381     return S_OK;
382 }
383 HRESULT WINAPI CIDLDataObj::InOperation(BOOL *pfInAsyncOp)
384 {
385     FIXME("(%p)->()\n", this);
386     return E_NOTIMPL;
387 }
388 HRESULT WINAPI CIDLDataObj::SetAsyncMode(BOOL fDoOpAsync)
389 {
390     TRACE("(%p)->()\n", this);
391     doasync = fDoOpAsync;
392     return S_OK;
393 }
394 
395 HRESULT WINAPI CIDLDataObj::StartOperation(IBindCtx *pbcReserved)
396 {
397     TRACE("(%p)->()\n", this);
398     return E_NOTIMPL;
399 }
400 HRESULT WINAPI CIDLDataObj::EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects)
401 {
402     TRACE("(%p)->()\n", this);
403     return E_NOTIMPL;
404 }
405 
406 
407 
408 /**************************************************************************
409 *  IDataObject_Constructor
410 */
411 HRESULT IDataObject_Constructor(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl, PCUIDLIST_RELATIVE_ARRAY apidl, UINT cidl, IDataObject **dataObject)
412 {
413     if (!dataObject)
414         return E_INVALIDARG;
415     return ShellObjectCreatorInit<CIDLDataObj>(hwndOwner, pMyPidl, apidl, cidl, IID_PPV_ARG(IDataObject, dataObject));
416 }
417 
418 /*************************************************************************
419  * SHCreateDataObject            [SHELL32.@]
420  *
421  */
422 
423 HRESULT WINAPI SHCreateDataObject(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, IDataObject *pdtInner, REFIID riid, void **ppv)
424 {
425     if (IsEqualIID(riid, IID_IDataObject))
426     {
427         return CIDLData_CreateFromIDArray(pidlFolder, cidl, apidl, (IDataObject **)ppv);
428     }
429     return E_FAIL;
430 }
431