1 #include <precomp.h> 2 3 /************************************************************************** 4 THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF 5 ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 6 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 7 PARTICULAR PURPOSE. 8 Author: Leon Finker 11/2000 9 Modifications: replaced ATL by STL, Martin Fuchs 7/2003 10 **************************************************************************/ 11 12 // dragdropimp.cpp: implementation of the IDataObjectImpl class. 13 ////////////////////////////////////////////////////////////////////// 14 15 //#include <shlobj.h> 16 //#include <assert.h> 17 18 //#include "dragdropimpl.h" 19 20 ////////////////////////////////////////////////////////////////////// 21 // IDataObjectImpl Class 22 ////////////////////////////////////////////////////////////////////// 23 24 IDataObjectImpl::IDataObjectImpl(IDropSourceImpl* pDropSource) 25 : super(IID_IDataObject), 26 m_pDropSource(pDropSource), 27 m_cRefCount(0) 28 { 29 } 30 31 IDataObjectImpl::~IDataObjectImpl() 32 { 33 for(StorageArray::iterator it=_storage.begin(); it!=_storage.end(); ++it) 34 ReleaseStgMedium(it->_medium); 35 } 36 37 STDMETHODIMP IDataObjectImpl::GetData( 38 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetcIn, 39 /* [out] */ STGMEDIUM __RPC_FAR *pmedium) 40 { 41 if (pformatetcIn == NULL || pmedium == NULL) 42 return E_INVALIDARG; 43 44 pmedium->hGlobal = NULL; 45 46 for(StorageArray::iterator it=_storage.begin(); it!=_storage.end(); ++it) 47 { 48 if (pformatetcIn->tymed & it->_format->tymed && 49 pformatetcIn->dwAspect == it->_format->dwAspect && 50 pformatetcIn->cfFormat == it->_format->cfFormat) 51 { 52 CopyMedium(pmedium, it->_medium, it->_format); 53 return S_OK; 54 } 55 } 56 57 return DV_E_FORMATETC; 58 } 59 60 STDMETHODIMP IDataObjectImpl::GetDataHere( 61 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc, 62 /* [out][in] */ STGMEDIUM __RPC_FAR *pmedium) 63 { 64 return E_NOTIMPL; 65 } 66 67 STDMETHODIMP IDataObjectImpl::QueryGetData( 68 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc) 69 { 70 if (pformatetc == NULL) 71 return E_INVALIDARG; 72 73 //support others if needed DVASPECT_THUMBNAIL //DVASPECT_ICON //DVASPECT_DOCPRINT 74 if (!(DVASPECT_CONTENT & pformatetc->dwAspect)) 75 return (DV_E_DVASPECT); 76 77 HRESULT hr = DV_E_TYMED; 78 79 for(StorageArray::iterator it=_storage.begin(); it!=_storage.end(); ++it) 80 { 81 if (pformatetc->tymed & it->_format->tymed) 82 { 83 if (pformatetc->cfFormat == it->_format->cfFormat) 84 return S_OK; 85 else 86 hr = DV_E_CLIPFORMAT; 87 } 88 else 89 hr = DV_E_TYMED; 90 } 91 92 return hr; 93 } 94 95 STDMETHODIMP IDataObjectImpl::GetCanonicalFormatEtc( 96 /* [unique][in] */ FORMATETC __RPC_FAR *pformatectIn, 97 /* [out] */ FORMATETC __RPC_FAR *pformatetcOut) 98 { 99 if (pformatetcOut == NULL) 100 return E_INVALIDARG; 101 102 return DATA_S_SAMEFORMATETC; 103 } 104 105 STDMETHODIMP IDataObjectImpl::SetData( 106 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc, 107 /* [unique][in] */ STGMEDIUM __RPC_FAR *pmedium, 108 /* [in] */ BOOL fRelease) 109 { 110 if (pformatetc == NULL || pmedium == NULL) 111 return E_INVALIDARG; 112 113 assert(pformatetc->tymed == pmedium->tymed); 114 FORMATETC* fetc=new FORMATETC; 115 STGMEDIUM* pStgMed = new STGMEDIUM; 116 117 if (fetc == NULL || pStgMed == NULL) 118 return E_OUTOFMEMORY; 119 120 ZeroMemory(fetc, sizeof(FORMATETC)); 121 ZeroMemory(pStgMed, sizeof(STGMEDIUM)); 122 123 *fetc = *pformatetc; 124 125 if (fRelease) 126 *pStgMed = *pmedium; 127 else 128 CopyMedium(pStgMed, pmedium, pformatetc); 129 130 DataStorage storage; 131 132 storage._format = fetc; 133 storage._medium = pStgMed; 134 135 _storage.push_back(storage); 136 137 return S_OK; 138 } 139 140 void IDataObjectImpl::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc) 141 { 142 switch(pMedSrc->tymed) 143 { 144 case TYMED_HGLOBAL: 145 pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal, pFmtSrc->cfFormat, 0); 146 break; 147 case TYMED_GDI: 148 pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap, pFmtSrc->cfFormat, 0); 149 break; 150 case TYMED_MFPICT: 151 pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict, pFmtSrc->cfFormat, 0); 152 break; 153 case TYMED_ENHMF: 154 pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile, pFmtSrc->cfFormat, 0); 155 break; 156 case TYMED_FILE: 157 pMedDest->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName, pFmtSrc->cfFormat, 0); 158 break; 159 case TYMED_ISTREAM: 160 pMedDest->pstm = pMedSrc->pstm; 161 pMedSrc->pstm->AddRef(); 162 break; 163 case TYMED_ISTORAGE: 164 pMedDest->pstg = pMedSrc->pstg; 165 pMedSrc->pstg->AddRef(); 166 break; 167 case TYMED_NULL: 168 default: 169 break; 170 } 171 pMedDest->tymed = pMedSrc->tymed; 172 pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease; 173 } 174 175 STDMETHODIMP IDataObjectImpl::EnumFormatEtc( 176 /* [in] */ DWORD dwDirection, 177 /* [out] */ IEnumFORMATETC __RPC_FAR *__RPC_FAR *ppenumFormatEtc) 178 { 179 if (ppenumFormatEtc == NULL) 180 return E_POINTER; 181 182 *ppenumFormatEtc=NULL; 183 switch (dwDirection) 184 { 185 case DATADIR_GET: 186 *ppenumFormatEtc = new EnumFormatEtcImpl(_storage); 187 188 if (!*ppenumFormatEtc) 189 return E_OUTOFMEMORY; 190 191 (*ppenumFormatEtc)->AddRef(); 192 break; 193 194 case DATADIR_SET: 195 default: 196 return E_NOTIMPL; 197 break; 198 } 199 200 return S_OK; 201 } 202 203 STDMETHODIMP IDataObjectImpl::DAdvise( 204 /* [in] */ FORMATETC __RPC_FAR *pformatetc, 205 /* [in] */ DWORD advf, 206 /* [unique][in] */ IAdviseSink __RPC_FAR *pAdvSink, 207 /* [out] */ DWORD __RPC_FAR *pdwConnection) 208 { 209 return OLE_E_ADVISENOTSUPPORTED; 210 } 211 212 STDMETHODIMP IDataObjectImpl::DUnadvise( 213 /* [in] */ DWORD dwConnection) 214 { 215 return E_NOTIMPL; 216 } 217 218 HRESULT STDMETHODCALLTYPE IDataObjectImpl::EnumDAdvise( 219 /* [out] */ IEnumSTATDATA __RPC_FAR *__RPC_FAR *ppenumAdvise) 220 { 221 return OLE_E_ADVISENOTSUPPORTED; 222 } 223 224 ////////////////////////////////////////////////////////////////////// 225 // IDropSourceImpl Class 226 ////////////////////////////////////////////////////////////////////// 227 228 STDMETHODIMP IDropSourceImpl::QueryContinueDrag( 229 /* [in] */ BOOL fEscapePressed, 230 /* [in] */ DWORD grfKeyState) 231 { 232 if (fEscapePressed) 233 return DRAGDROP_S_CANCEL; 234 if (!(grfKeyState & (MK_LBUTTON|MK_RBUTTON))) 235 { 236 m_bDropped = true; 237 return DRAGDROP_S_DROP; 238 } 239 240 return S_OK; 241 242 } 243 244 STDMETHODIMP IDropSourceImpl::GiveFeedback( 245 /* [in] */ DWORD dwEffect) 246 { 247 return DRAGDROP_S_USEDEFAULTCURSORS; 248 } 249 250 ////////////////////////////////////////////////////////////////////// 251 // EnumFormatEtcImpl Class 252 ////////////////////////////////////////////////////////////////////// 253 254 EnumFormatEtcImpl::EnumFormatEtcImpl(const FormatArray& ArrFE) 255 : super(IID_IEnumFORMATETC), 256 m_cRefCount(0), 257 m_iCur(0) 258 { 259 for(FormatArray::const_iterator it=ArrFE.begin(); it!=ArrFE.end(); ++it) 260 m_pFmtEtc.push_back(*it); 261 } 262 263 EnumFormatEtcImpl::EnumFormatEtcImpl(const StorageArray& ArrFE) 264 : super(IID_IEnumFORMATETC), 265 m_cRefCount(0), 266 m_iCur(0) 267 { 268 for(StorageArray::const_iterator it=ArrFE.begin(); it!=ArrFE.end(); ++it) 269 m_pFmtEtc.push_back(*it->_format); 270 } 271 272 STDMETHODIMP EnumFormatEtcImpl::Next(ULONG celt,LPFORMATETC lpFormatEtc, ULONG* pceltFetched) 273 { 274 if (pceltFetched != NULL) 275 *pceltFetched=0; 276 277 ULONG cReturn = celt; 278 279 if (celt <= 0 || lpFormatEtc == NULL || m_iCur >= m_pFmtEtc.size()) 280 return S_FALSE; 281 282 if (pceltFetched == NULL && celt != 1) // pceltFetched can be NULL only for 1 item request 283 return S_FALSE; 284 285 while (m_iCur < m_pFmtEtc.size() && cReturn > 0) 286 { 287 *lpFormatEtc++ = m_pFmtEtc[m_iCur++]; 288 --cReturn; 289 } 290 if (pceltFetched != NULL) 291 *pceltFetched = celt - cReturn; 292 293 return (cReturn == 0) ? S_OK : S_FALSE; 294 } 295 296 STDMETHODIMP EnumFormatEtcImpl::Skip(ULONG celt) 297 { 298 if ((m_iCur + int(celt)) >= m_pFmtEtc.size()) 299 return S_FALSE; 300 301 m_iCur += celt; 302 return S_OK; 303 } 304 305 STDMETHODIMP EnumFormatEtcImpl::Reset(void) 306 { 307 m_iCur = 0; 308 return S_OK; 309 } 310 311 STDMETHODIMP EnumFormatEtcImpl::Clone(IEnumFORMATETC** ppCloneEnumFormatEtc) 312 { 313 if (ppCloneEnumFormatEtc == NULL) 314 return E_POINTER; 315 316 EnumFormatEtcImpl* newEnum = new EnumFormatEtcImpl(m_pFmtEtc); 317 318 if (!newEnum) 319 return E_OUTOFMEMORY; 320 321 newEnum->AddRef(); 322 newEnum->m_iCur = m_iCur; 323 *ppCloneEnumFormatEtc = newEnum; 324 325 return S_OK; 326 } 327 328 ////////////////////////////////////////////////////////////////////// 329 // IDropTargetImpl Class 330 ////////////////////////////////////////////////////////////////////// 331 IDropTargetImpl::IDropTargetImpl(HWND hTargetWnd) 332 : m_cRefCount(0), 333 m_bAllowDrop(false), 334 m_pDropTargetHelper(NULL), 335 m_pSupportedFrmt(NULL), 336 m_hTargetWnd(hTargetWnd) 337 { 338 assert(m_hTargetWnd != NULL); 339 340 if (FAILED(CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER, 341 IID_IDropTargetHelper,(LPVOID*)&m_pDropTargetHelper))) 342 m_pDropTargetHelper = NULL; 343 } 344 345 IDropTargetImpl::~IDropTargetImpl() 346 { 347 if (m_pDropTargetHelper != NULL) 348 { 349 m_pDropTargetHelper->Release(); 350 m_pDropTargetHelper = NULL; 351 } 352 } 353 354 HRESULT STDMETHODCALLTYPE IDropTargetImpl::QueryInterface( /* [in] */ REFIID riid, 355 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) 356 { 357 *ppvObject = NULL; 358 if (IID_IUnknown==riid || IID_IDropTarget==riid) 359 *ppvObject=this; 360 361 if (*ppvObject != NULL) 362 { 363 ((LPUNKNOWN)*ppvObject)->AddRef(); 364 return S_OK; 365 } 366 367 return E_NOINTERFACE; 368 } 369 370 ULONG STDMETHODCALLTYPE IDropTargetImpl::Release() 371 { 372 long nTemp = --m_cRefCount; 373 374 assert(nTemp >= 0); 375 376 if (nTemp == 0) 377 delete this; 378 379 return nTemp; 380 } 381 382 bool IDropTargetImpl::QueryDrop(DWORD grfKeyState, LPDWORD pdwEffect) 383 { 384 DWORD dwOKEffects = *pdwEffect; 385 386 if (!m_bAllowDrop) 387 { 388 *pdwEffect = DROPEFFECT_NONE; 389 return false; 390 } 391 392 //CTRL+SHIFT -- DROPEFFECT_LINK 393 //CTRL -- DROPEFFECT_COPY 394 //SHIFT -- DROPEFFECT_MOVE 395 //no modifier -- DROPEFFECT_MOVE or whatever is allowed by src 396 *pdwEffect = (grfKeyState & MK_CONTROL) ? 397 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY ): 398 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_MOVE : DROPEFFECT_NONE ); 399 if (*pdwEffect == 0) 400 { 401 // No modifier keys used by user while dragging. 402 if (DROPEFFECT_COPY & dwOKEffects) 403 *pdwEffect = DROPEFFECT_COPY; 404 else if (DROPEFFECT_MOVE & dwOKEffects) 405 *pdwEffect = DROPEFFECT_MOVE; 406 else if (DROPEFFECT_LINK & dwOKEffects) 407 *pdwEffect = DROPEFFECT_LINK; 408 else 409 { 410 *pdwEffect = DROPEFFECT_NONE; 411 } 412 } 413 else 414 { 415 // Check if the drag source application allows the drop effect desired by user. 416 // The drag source specifies this in DoDragDrop 417 if (!(*pdwEffect & dwOKEffects)) 418 *pdwEffect = DROPEFFECT_NONE; 419 } 420 421 return (DROPEFFECT_NONE == *pdwEffect)?false:true; 422 } 423 424 HRESULT STDMETHODCALLTYPE IDropTargetImpl::DragEnter( 425 /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, 426 /* [in] */ DWORD grfKeyState, 427 /* [in] */ POINTL pt, 428 /* [out][in] */ DWORD __RPC_FAR *pdwEffect) 429 { 430 if (pDataObj == NULL) 431 return E_INVALIDARG; 432 433 if (m_pDropTargetHelper) 434 m_pDropTargetHelper->DragEnter(m_hTargetWnd, pDataObj, (LPPOINT)&pt, *pdwEffect); 435 436 //IEnumFORMATETC* pEnum; 437 //pDataObj->EnumFormatEtc(DATADIR_GET,&pEnum); 438 //FORMATETC ftm; 439 //for() 440 //pEnum->Next(1,&ftm,0); 441 //pEnum->Release(); 442 m_pSupportedFrmt = NULL; 443 444 for(FormatArray::iterator it=m_formatetc.begin(); it!=m_formatetc.end(); ++it) 445 { 446 m_bAllowDrop = (pDataObj->QueryGetData(&*it) == S_OK)? true: false; 447 448 if (m_bAllowDrop) 449 { 450 m_pSupportedFrmt = &*it; 451 break; 452 } 453 } 454 455 QueryDrop(grfKeyState, pdwEffect); 456 457 return S_OK; 458 } 459 460 HRESULT STDMETHODCALLTYPE IDropTargetImpl::DragOver( 461 /* [in] */ DWORD grfKeyState, 462 /* [in] */ POINTL pt, 463 /* [out][in] */ DWORD __RPC_FAR *pdwEffect) 464 { 465 if (m_pDropTargetHelper) 466 m_pDropTargetHelper->DragOver((LPPOINT)&pt, *pdwEffect); 467 468 QueryDrop(grfKeyState, pdwEffect); 469 470 return S_OK; 471 } 472 473 HRESULT STDMETHODCALLTYPE IDropTargetImpl::DragLeave() 474 { 475 if (m_pDropTargetHelper) 476 m_pDropTargetHelper->DragLeave(); 477 478 m_bAllowDrop = false; 479 m_pSupportedFrmt = NULL; 480 481 return S_OK; 482 } 483 484 HRESULT STDMETHODCALLTYPE IDropTargetImpl::Drop( 485 /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, 486 /* [in] */ DWORD grfKeyState, /* [in] */ POINTL pt, 487 /* [out][in] */ DWORD __RPC_FAR *pdwEffect) 488 { 489 if (pDataObj == NULL) 490 return E_INVALIDARG; 491 492 if (m_pDropTargetHelper) 493 m_pDropTargetHelper->Drop(pDataObj, (LPPOINT)&pt, *pdwEffect); 494 495 if (QueryDrop(grfKeyState, pdwEffect)) 496 { 497 if (m_bAllowDrop && m_pSupportedFrmt != NULL) 498 { 499 STGMEDIUM medium; 500 501 if (pDataObj->GetData(m_pSupportedFrmt, &medium) == S_OK) 502 { 503 if (OnDrop(m_pSupportedFrmt, medium, pdwEffect)) //does derive class wants us to free medium? 504 ReleaseStgMedium(&medium); 505 } 506 } 507 } 508 509 m_bAllowDrop = false; 510 *pdwEffect = DROPEFFECT_NONE; 511 m_pSupportedFrmt = NULL; 512 513 return S_OK; 514 } 515