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 for (int n = 0; n < m_Formats.GetSize(); ++n) 240 { 241 const FORMATETC& fmt = m_Formats[n]; 242 if (fmt.cfFormat == pformatetcIn->cfFormat && 243 fmt.dwAspect == pformatetcIn->dwAspect && 244 fmt.tymed == pformatetcIn->tymed) 245 { 246 if (pformatetcIn->tymed != TYMED_HGLOBAL) 247 { 248 UNIMPLEMENTED; 249 return E_INVALIDARG; 250 } 251 else 252 { 253 *pmedium = m_Storage[n]; 254 return QueryInterface(IID_PPV_ARG(IUnknown, &pmedium->pUnkForRelease)); 255 } 256 } 257 } 258 259 return E_INVALIDARG; 260 } 261 262 HRESULT WINAPI CIDLDataObj::GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium) 263 { 264 FIXME("(%p)->()\n", this); 265 return E_NOTIMPL; 266 } 267 268 HRESULT WINAPI CIDLDataObj::QueryGetData(LPFORMATETC pformatetc) 269 { 270 TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", this, pformatetc->cfFormat, pformatetc->tymed); 271 272 for (int n = 0; n < m_Formats.GetSize(); ++n) 273 { 274 const FORMATETC& fmt = m_Formats[n]; 275 if (fmt.cfFormat == pformatetc->cfFormat && 276 fmt.dwAspect == pformatetc->dwAspect && 277 fmt.tymed == pformatetc->tymed) 278 { 279 return S_OK; 280 } 281 } 282 283 return S_FALSE; 284 } 285 286 HRESULT WINAPI CIDLDataObj::GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut) 287 { 288 //FIXME("(%p)->()\n", this); 289 return DATA_S_SAMEFORMATETC; 290 } 291 292 HRESULT WINAPI CIDLDataObj::SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease) 293 { 294 if (!fRelease) 295 return E_INVALIDARG; 296 297 for (int n = 0; n < m_Formats.GetSize(); ++n) 298 { 299 const FORMATETC& fmt = m_Formats[n]; 300 if (fmt.cfFormat == pformatetc->cfFormat && 301 fmt.dwAspect == pformatetc->dwAspect && 302 fmt.tymed == pformatetc->tymed) 303 { 304 ReleaseStgMedium(&m_Storage[n]); 305 m_Storage[n] = *pmedium; 306 return S_OK; 307 } 308 } 309 310 m_Formats.Add(*pformatetc); 311 m_Storage.Add(*pmedium); 312 313 return S_OK; 314 } 315 316 HRESULT WINAPI CIDLDataObj::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) 317 { 318 TRACE("(%p)->()\n", this); 319 *ppenumFormatEtc = NULL; 320 321 /* only get data */ 322 if (DATADIR_GET == dwDirection) 323 { 324 return IEnumFORMATETC_Constructor(m_Formats.GetSize(), m_Formats.GetData(), ppenumFormatEtc); 325 } 326 327 return E_NOTIMPL; 328 } 329 330 HRESULT WINAPI CIDLDataObj::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) 331 { 332 return OLE_E_ADVISENOTSUPPORTED; 333 } 334 335 HRESULT WINAPI CIDLDataObj::DUnadvise(DWORD dwConnection) 336 { 337 return OLE_E_ADVISENOTSUPPORTED; 338 } 339 340 HRESULT WINAPI CIDLDataObj::EnumDAdvise(IEnumSTATDATA **ppenumAdvise) 341 { 342 return OLE_E_ADVISENOTSUPPORTED; 343 } 344 345 HRESULT WINAPI CIDLDataObj::GetAsyncMode(BOOL *pfIsOpAsync) 346 { 347 TRACE("(%p)->()\n", this); 348 *pfIsOpAsync = m_doasync; 349 return S_OK; 350 } 351 HRESULT WINAPI CIDLDataObj::InOperation(BOOL *pfInAsyncOp) 352 { 353 FIXME("(%p)->()\n", this); 354 return E_NOTIMPL; 355 } 356 HRESULT WINAPI CIDLDataObj::SetAsyncMode(BOOL fDoOpAsync) 357 { 358 TRACE("(%p)->()\n", this); 359 m_doasync = fDoOpAsync; 360 return S_OK; 361 } 362 363 HRESULT WINAPI CIDLDataObj::StartOperation(IBindCtx *pbcReserved) 364 { 365 TRACE("(%p)->()\n", this); 366 return E_NOTIMPL; 367 } 368 HRESULT WINAPI CIDLDataObj::EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects) 369 { 370 TRACE("(%p)->()\n", this); 371 return E_NOTIMPL; 372 } 373 374 375 376 /************************************************************************** 377 * IDataObject_Constructor 378 */ 379 HRESULT IDataObject_Constructor(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl, PCUIDLIST_RELATIVE_ARRAY apidl, UINT cidl, BOOL bExtendedObject, IDataObject **dataObject) 380 { 381 if (!dataObject) 382 return E_INVALIDARG; 383 return ShellObjectCreatorInit<CIDLDataObj>(hwndOwner, pMyPidl, apidl, cidl, bExtendedObject, IID_PPV_ARG(IDataObject, dataObject)); 384 } 385 386 /************************************************************************* 387 * SHCreateDataObject [SHELL32.@] 388 * 389 */ 390 391 HRESULT WINAPI SHCreateDataObject(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, IDataObject *pdtInner, REFIID riid, void **ppv) 392 { 393 if (IsEqualIID(riid, IID_IDataObject)) 394 { 395 if (pdtInner) 396 UNIMPLEMENTED; 397 return IDataObject_Constructor(NULL, pidlFolder, apidl, cidl, TRUE, (IDataObject **)ppv); 398 } 399 return E_FAIL; 400 } 401