[SHELL32] CCopyToMenu/CMoveToMenu: Check if this_ is NULL
[reactos.git] / dll / win32 / shell32 / CIDLDataObj.cpp
1 /*
2 * PROJECT: shell32
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: IEnumFORMATETC, IDataObject implementation
5 * COPYRIGHT: Copyright 1998, 1999 <juergen.schmied@metronet.de>
6 * Copyright 2019 Mark Jansen (mark.jansen@reactos.org)
7 */
8
9 #include "precomp.h"
10
11 WINE_DEFAULT_DEBUG_CHANNEL(shell);
12
13 /***********************************************************************
14 * IEnumFORMATETC implementation
15 */
16
17 class IEnumFORMATETCImpl :
18 public CComObjectRootEx<CComMultiThreadModelNoCS>,
19 public IEnumFORMATETC
20 {
21 private:
22 UINT posFmt;
23 UINT countFmt;
24 LPFORMATETC pFmt;
25 public:
26 IEnumFORMATETCImpl();
27 ~IEnumFORMATETCImpl();
28 HRESULT WINAPI Initialize(UINT cfmt, const FORMATETC afmt[]);
29
30 // *****************
31 virtual HRESULT WINAPI Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed);
32 virtual HRESULT WINAPI Skip(ULONG celt);
33 virtual HRESULT WINAPI Reset();
34 virtual HRESULT WINAPI Clone(LPENUMFORMATETC* ppenum);
35
36 BEGIN_COM_MAP(IEnumFORMATETCImpl)
37 COM_INTERFACE_ENTRY_IID(IID_IEnumFORMATETC, IEnumFORMATETC)
38 END_COM_MAP()
39 };
40
41 IEnumFORMATETCImpl::IEnumFORMATETCImpl()
42 {
43 posFmt = 0;
44 countFmt = 0;
45 pFmt = NULL;
46 }
47
48 IEnumFORMATETCImpl::~IEnumFORMATETCImpl()
49 {
50 }
51
52 HRESULT WINAPI IEnumFORMATETCImpl::Initialize(UINT cfmt, const FORMATETC afmt[])
53 {
54 DWORD size;
55
56 size = cfmt * sizeof(FORMATETC);
57 countFmt = cfmt;
58 pFmt = (LPFORMATETC)SHAlloc(size);
59 if (pFmt == NULL)
60 return E_OUTOFMEMORY;
61
62 memcpy(pFmt, afmt, size);
63 return S_OK;
64 }
65
66 HRESULT WINAPI IEnumFORMATETCImpl::Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
67 {
68 UINT i;
69
70 TRACE("(%p)->(%u,%p)\n", this, celt, rgelt);
71
72 if (!pFmt)
73 return S_FALSE;
74 if (!rgelt)
75 return E_INVALIDARG;
76 if (pceltFethed)
77 *pceltFethed = 0;
78
79 for (i = 0; posFmt < countFmt && celt > i; i++)
80 {
81 *rgelt++ = pFmt[posFmt++];
82 }
83
84 if (pceltFethed)
85 *pceltFethed = i;
86
87 return ((i == celt) ? S_OK : S_FALSE);
88 }
89
90 HRESULT WINAPI IEnumFORMATETCImpl::Skip(ULONG celt)
91 {
92 TRACE("(%p)->(num=%u)\n", this, celt);
93
94 if (posFmt + celt >= countFmt)
95 return S_FALSE;
96 posFmt += celt;
97 return S_OK;
98 }
99
100 HRESULT WINAPI IEnumFORMATETCImpl::Reset()
101 {
102 TRACE("(%p)->()\n", this);
103
104 posFmt = 0;
105 return S_OK;
106 }
107
108 HRESULT WINAPI IEnumFORMATETCImpl::Clone(LPENUMFORMATETC* ppenum)
109 {
110 HRESULT hResult;
111
112 TRACE("(%p)->(ppenum=%p)\n", this, ppenum);
113
114 if (!ppenum) return E_INVALIDARG;
115 hResult = IEnumFORMATETC_Constructor(countFmt, pFmt, ppenum);
116 if (FAILED_UNEXPECTEDLY(hResult))
117 return hResult;
118 return (*ppenum)->Skip(posFmt);
119 }
120
121 HRESULT IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[], IEnumFORMATETC **ppFormat)
122 {
123 return ShellObjectCreatorInit<IEnumFORMATETCImpl>(cfmt, afmt, IID_PPV_ARG(IEnumFORMATETC, ppFormat));
124 }
125
126
127 /***********************************************************************
128 * IDataObject implementation
129 * For now (2019-10-12) it's compatible with 2k3's data object
130 * See shell32_apitest!CIDLData for changes between versions
131 */
132
133 class CIDLDataObj :
134 public CComObjectRootEx<CComMultiThreadModelNoCS>,
135 public IDataObject,
136 public IAsyncOperation
137 {
138 private:
139 CSimpleArray<FORMATETC> m_Formats;
140 CSimpleArray<STGMEDIUM> m_Storage;
141 UINT m_cfShellIDList;
142 BOOL m_doasync;
143 public:
144 CIDLDataObj();
145 ~CIDLDataObj();
146 HRESULT WINAPI Initialize(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl, PCUIDLIST_RELATIVE_ARRAY apidlx, UINT cidlx, BOOL bAddAdditionalFormats);
147
148 // *** IDataObject methods ***
149 virtual HRESULT WINAPI GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium);
150 virtual HRESULT WINAPI GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium);
151 virtual HRESULT WINAPI QueryGetData(LPFORMATETC pformatetc);
152 virtual HRESULT WINAPI GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut);
153 virtual HRESULT WINAPI SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease);
154 virtual HRESULT WINAPI EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc);
155 virtual HRESULT WINAPI DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
156 virtual HRESULT WINAPI DUnadvise(DWORD dwConnection);
157 virtual HRESULT WINAPI EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
158
159 // *** IAsyncOperation methods ***
160 virtual HRESULT WINAPI SetAsyncMode(BOOL fDoOpAsync);
161 virtual HRESULT WINAPI GetAsyncMode(BOOL *pfIsOpAsync);
162 virtual HRESULT WINAPI StartOperation(IBindCtx *pbcReserved);
163 virtual HRESULT WINAPI InOperation(BOOL *pfInAsyncOp);
164 virtual HRESULT WINAPI EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects);
165
166 BEGIN_COM_MAP(CIDLDataObj)
167 COM_INTERFACE_ENTRY_IID(IID_IDataObject, IDataObject)
168 COM_INTERFACE_ENTRY_IID(IID_IAsyncOperation, IAsyncOperation)
169 END_COM_MAP()
170 };
171
172 CIDLDataObj::CIDLDataObj()
173 {
174 m_cfShellIDList = 0;
175 m_doasync = FALSE;
176 }
177
178 CIDLDataObj::~CIDLDataObj()
179 {
180 TRACE(" destroying IDataObject(%p)\n", this);
181
182 for (int n = 0; n < m_Storage.GetSize(); ++n)
183 {
184 ReleaseStgMedium(&m_Storage[n]);
185 }
186 m_Formats.RemoveAll();
187 m_Storage.RemoveAll();
188 }
189
190 HRESULT WINAPI CIDLDataObj::Initialize(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl, PCUIDLIST_RELATIVE_ARRAY apidlx, UINT cidlx, BOOL bAddAdditionalFormats)
191 {
192 HGLOBAL hida = RenderSHELLIDLIST((LPITEMIDLIST)pMyPidl, (LPITEMIDLIST*)apidlx, cidlx);
193 if (!hida)
194 {
195 ERR("Failed to render " CFSTR_SHELLIDLISTA "\n");
196 return E_OUTOFMEMORY;
197 }
198
199 m_cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
200
201 FORMATETC Format = { (CLIPFORMAT)m_cfShellIDList, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
202 STGMEDIUM medium = {0};
203 medium.tymed = TYMED_HGLOBAL;
204 medium.hGlobal = hida;
205 HRESULT hr = SetData(&Format, &medium, TRUE);
206 if (!FAILED_UNEXPECTEDLY(hr) && bAddAdditionalFormats)
207 {
208 Format.cfFormat = CF_HDROP;
209 medium.hGlobal = RenderHDROP((LPITEMIDLIST)pMyPidl, (LPITEMIDLIST*)apidlx, cidlx);
210 hr = SetData(&Format, &medium, TRUE);
211 if (FAILED_UNEXPECTEDLY(hr))
212 return hr;
213
214 Format.cfFormat = RegisterClipboardFormatA(CFSTR_FILENAMEA);
215 medium.hGlobal = RenderFILENAMEA((LPITEMIDLIST)pMyPidl, (LPITEMIDLIST*)apidlx, cidlx);
216 hr = SetData(&Format, &medium, TRUE);
217 if (FAILED_UNEXPECTEDLY(hr))
218 return hr;
219
220 Format.cfFormat = RegisterClipboardFormatW(CFSTR_FILENAMEW);
221 medium.hGlobal = RenderFILENAMEW((LPITEMIDLIST)pMyPidl, (LPITEMIDLIST*)apidlx, cidlx);
222 hr = SetData(&Format, &medium, TRUE);
223 if (FAILED_UNEXPECTEDLY(hr))
224 return hr;
225 }
226
227 return hr;
228 }
229
230
231 HRESULT WINAPI CIDLDataObj::GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium)
232 {
233 if (TRACE_ON(shell))
234 {
235 char szTemp[256] = {0};
236 GetClipboardFormatNameA (pformatetcIn->cfFormat, szTemp, 256);
237 TRACE("(%p)->(%p %p format=%s)\n", this, pformatetcIn, pmedium, szTemp);
238 }
239 pmedium->hGlobal = NULL;
240 pmedium->pUnkForRelease = NULL;
241 for (int n = 0; n < m_Formats.GetSize(); ++n)
242 {
243 const FORMATETC& fmt = m_Formats[n];
244 if (fmt.cfFormat == pformatetcIn->cfFormat &&
245 fmt.dwAspect == pformatetcIn->dwAspect &&
246 fmt.tymed == pformatetcIn->tymed)
247 {
248 if (pformatetcIn->tymed != TYMED_HGLOBAL)
249 {
250 UNIMPLEMENTED;
251 return E_INVALIDARG;
252 }
253 else
254 {
255 *pmedium = m_Storage[n];
256 return QueryInterface(IID_PPV_ARG(IUnknown, &pmedium->pUnkForRelease));
257 }
258 }
259 }
260
261 return E_INVALIDARG;
262 }
263
264 HRESULT WINAPI CIDLDataObj::GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium)
265 {
266 FIXME("(%p)->()\n", this);
267 return E_NOTIMPL;
268 }
269
270 HRESULT WINAPI CIDLDataObj::QueryGetData(LPFORMATETC pformatetc)
271 {
272 TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", this, pformatetc->cfFormat, pformatetc->tymed);
273
274 for (int n = 0; n < m_Formats.GetSize(); ++n)
275 {
276 const FORMATETC& fmt = m_Formats[n];
277 if (fmt.cfFormat == pformatetc->cfFormat &&
278 fmt.dwAspect == pformatetc->dwAspect &&
279 fmt.tymed == pformatetc->tymed)
280 {
281 return S_OK;
282 }
283 }
284
285 return S_FALSE;
286 }
287
288 HRESULT WINAPI CIDLDataObj::GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut)
289 {
290 //FIXME("(%p)->()\n", this);
291 return DATA_S_SAMEFORMATETC;
292 }
293
294 HRESULT WINAPI CIDLDataObj::SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
295 {
296 if (!fRelease)
297 return E_INVALIDARG;
298
299 for (int n = 0; n < m_Formats.GetSize(); ++n)
300 {
301 const FORMATETC& fmt = m_Formats[n];
302 if (fmt.cfFormat == pformatetc->cfFormat &&
303 fmt.dwAspect == pformatetc->dwAspect &&
304 fmt.tymed == pformatetc->tymed)
305 {
306 ReleaseStgMedium(&m_Storage[n]);
307 m_Storage[n] = *pmedium;
308 return S_OK;
309 }
310 }
311
312 m_Formats.Add(*pformatetc);
313 m_Storage.Add(*pmedium);
314
315 return S_OK;
316 }
317
318 HRESULT WINAPI CIDLDataObj::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(m_Formats.GetSize(), m_Formats.GetData(), ppenumFormatEtc);
327 }
328
329 return E_NOTIMPL;
330 }
331
332 HRESULT WINAPI CIDLDataObj::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
333 {
334 return OLE_E_ADVISENOTSUPPORTED;
335 }
336
337 HRESULT WINAPI CIDLDataObj::DUnadvise(DWORD dwConnection)
338 {
339 return OLE_E_ADVISENOTSUPPORTED;
340 }
341
342 HRESULT WINAPI CIDLDataObj::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
343 {
344 return OLE_E_ADVISENOTSUPPORTED;
345 }
346
347 HRESULT WINAPI CIDLDataObj::GetAsyncMode(BOOL *pfIsOpAsync)
348 {
349 TRACE("(%p)->()\n", this);
350 *pfIsOpAsync = m_doasync;
351 return S_OK;
352 }
353 HRESULT WINAPI CIDLDataObj::InOperation(BOOL *pfInAsyncOp)
354 {
355 FIXME("(%p)->()\n", this);
356 return E_NOTIMPL;
357 }
358 HRESULT WINAPI CIDLDataObj::SetAsyncMode(BOOL fDoOpAsync)
359 {
360 TRACE("(%p)->()\n", this);
361 m_doasync = fDoOpAsync;
362 return S_OK;
363 }
364
365 HRESULT WINAPI CIDLDataObj::StartOperation(IBindCtx *pbcReserved)
366 {
367 TRACE("(%p)->()\n", this);
368 return E_NOTIMPL;
369 }
370 HRESULT WINAPI CIDLDataObj::EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects)
371 {
372 TRACE("(%p)->()\n", this);
373 return E_NOTIMPL;
374 }
375
376
377
378 /**************************************************************************
379 * IDataObject_Constructor
380 */
381 HRESULT IDataObject_Constructor(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl, PCUIDLIST_RELATIVE_ARRAY apidl, UINT cidl, BOOL bExtendedObject, IDataObject **dataObject)
382 {
383 if (!dataObject)
384 return E_INVALIDARG;
385 return ShellObjectCreatorInit<CIDLDataObj>(hwndOwner, pMyPidl, apidl, cidl, bExtendedObject, IID_PPV_ARG(IDataObject, dataObject));
386 }
387
388 /*************************************************************************
389 * SHCreateDataObject [SHELL32.@]
390 *
391 */
392
393 HRESULT WINAPI SHCreateDataObject(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, IDataObject *pdtInner, REFIID riid, void **ppv)
394 {
395 if (IsEqualIID(riid, IID_IDataObject))
396 {
397 if (pdtInner)
398 UNIMPLEMENTED;
399 return IDataObject_Constructor(NULL, pidlFolder, apidl, cidl, TRUE, (IDataObject **)ppv);
400 }
401 return E_FAIL;
402 }
403
404 /*************************************************************************
405 * SHCreateFileDataObject [SHELL32.740]
406 *
407 */
408
409 HRESULT WINAPI SHCreateFileDataObject(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, IDataObject* pDataInner, IDataObject** ppDataObj)
410 {
411 if (pDataInner)
412 UNIMPLEMENTED;
413 return IDataObject_Constructor(NULL, pidlFolder, apidl, cidl, TRUE, ppDataObj);
414 }