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