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 STDMETHOD(Next)(ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed) override; 32 STDMETHOD(Skip)(ULONG celt) override; 33 STDMETHOD(Reset)() override; 34 STDMETHOD(Clone)(LPENUMFORMATETC* ppenum) override; 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 STDMETHOD(GetData)(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium) override; 150 STDMETHOD(GetDataHere)(LPFORMATETC pformatetc, STGMEDIUM *pmedium) override; 151 STDMETHOD(QueryGetData)(LPFORMATETC pformatetc) override; 152 STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut) override; 153 STDMETHOD(SetData)(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease) override; 154 STDMETHOD(EnumFormatEtc)(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) override; 155 STDMETHOD(DAdvise)(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) override; 156 STDMETHOD(DUnadvise)(DWORD dwConnection) override; 157 STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise) override; 158 159 // *** IAsyncOperation methods *** 160 STDMETHOD(SetAsyncMode)(BOOL fDoOpAsync) override; 161 STDMETHOD(GetAsyncMode)(BOOL *pfIsOpAsync) override; 162 STDMETHOD(StartOperation)(IBindCtx *pbcReserved) override; 163 STDMETHOD(InOperation)(BOOL *pfInAsyncOp) override; 164 STDMETHOD(EndOperation)(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects) override; 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 } 415