X-Git-Url: http://git.jankratochvil.net/?p=reactos.git;a=blobdiff_plain;f=subsys%2Fsystem%2Fexplorer%2Futility%2Fdragdropimpl.cpp;fp=subsys%2Fsystem%2Fexplorer%2Futility%2Fdragdropimpl.cpp;h=28107abb454aecea7f6189667f17897cd0dbbb94;hp=0000000000000000000000000000000000000000;hb=ee8b63255465d8c28be3e7bd11628015708fc1ab;hpb=c99688ef1ab339c8746ecc385bde679623084c71 diff --git a/subsys/system/explorer/utility/dragdropimpl.cpp b/subsys/system/explorer/utility/dragdropimpl.cpp new file mode 100644 index 0000000..28107ab --- /dev/null +++ b/subsys/system/explorer/utility/dragdropimpl.cpp @@ -0,0 +1,592 @@ +/************************************************************************** + THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF + ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A + PARTICULAR PURPOSE. + Author: Leon Finker 11/2000 + Modifications: replaced ATL by STL, Martin Fuchs 7/2003 +**************************************************************************/ + +// dragdropimp.cpp: implementation of the IDataObjectImpl class. +////////////////////////////////////////////////////////////////////// +#include +#include + +#include "dragdropimpl.h" + +////////////////////////////////////////////////////////////////////// +// IDataObjectImpl Class +////////////////////////////////////////////////////////////////////// + +IDataObjectImpl::IDataObjectImpl(IDropSourceImpl* pDropSource): + m_cRefCount(0), + m_pDropSource(pDropSource) +{ +} + +IDataObjectImpl::~IDataObjectImpl() +{ + for(StorageArray::iterator it=_storage.begin(); it!=_storage.end(); ++it) + ReleaseStgMedium(it->_medium); +} + +STDMETHODIMP IDataObjectImpl::QueryInterface(/* [in] */ REFIID riid, +/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) +{ + *ppvObject = NULL; + if (IID_IUnknown==riid || IID_IDataObject==riid) + *ppvObject=this; + /*if (riid == IID_IAsyncOperation) + *ppvObject=(IAsyncOperation*)this;*/ + if (NULL!=*ppvObject) + { + ((LPUNKNOWN)*ppvObject)->AddRef(); + return S_OK; + } + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) IDataObjectImpl::AddRef() +{ + return ++m_cRefCount; +} + +STDMETHODIMP_(ULONG) IDataObjectImpl::Release() +{ + long nTemp = --m_cRefCount; + + if (nTemp == 0) + delete this; + + return nTemp; +} + +STDMETHODIMP IDataObjectImpl::GetData( + /* [unique][in] */ FORMATETC __RPC_FAR *pformatetcIn, + /* [out] */ STGMEDIUM __RPC_FAR *pmedium) +{ + if (pformatetcIn == NULL || pmedium == NULL) + return E_INVALIDARG; + + pmedium->hGlobal = NULL; + + for(StorageArray::iterator it=_storage.begin(); it!=_storage.end(); ++it) + { + if (pformatetcIn->tymed & it->_format->tymed && + pformatetcIn->dwAspect == it->_format->dwAspect && + pformatetcIn->cfFormat == it->_format->cfFormat) + { + CopyMedium(pmedium, it->_medium, it->_format); + return S_OK; + } + } + + return DV_E_FORMATETC; +} + +STDMETHODIMP IDataObjectImpl::GetDataHere( + /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc, + /* [out][in] */ STGMEDIUM __RPC_FAR *pmedium) +{ + return E_NOTIMPL; +} + +STDMETHODIMP IDataObjectImpl::QueryGetData( + /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc) +{ + if (pformatetc == NULL) + return E_INVALIDARG; + + //support others if needed DVASPECT_THUMBNAIL //DVASPECT_ICON //DVASPECT_DOCPRINT + if (!(DVASPECT_CONTENT & pformatetc->dwAspect)) + return (DV_E_DVASPECT); + + HRESULT hr = DV_E_TYMED; + + for(StorageArray::iterator it=_storage.begin(); it!=_storage.end(); ++it) + { + if (pformatetc->tymed & it->_format->tymed) + { + if (pformatetc->cfFormat == it->_format->cfFormat) + return S_OK; + else + hr = DV_E_CLIPFORMAT; + } + else + hr = DV_E_TYMED; + } + return hr; +} + +STDMETHODIMP IDataObjectImpl::GetCanonicalFormatEtc( + /* [unique][in] */ FORMATETC __RPC_FAR *pformatectIn, + /* [out] */ FORMATETC __RPC_FAR *pformatetcOut) +{ + if (pformatetcOut == NULL) + return E_INVALIDARG; + + return DATA_S_SAMEFORMATETC; +} + +STDMETHODIMP IDataObjectImpl::SetData( + /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc, + /* [unique][in] */ STGMEDIUM __RPC_FAR *pmedium, + /* [in] */ BOOL fRelease) +{ + if (pformatetc == NULL || pmedium == NULL) + return E_INVALIDARG; + + assert(pformatetc->tymed == pmedium->tymed); + FORMATETC* fetc=new FORMATETC; + STGMEDIUM* pStgMed = new STGMEDIUM; + + if (fetc == NULL || pStgMed == NULL) + return E_OUTOFMEMORY; + + ZeroMemory(fetc, sizeof(FORMATETC)); + ZeroMemory(pStgMed, sizeof(STGMEDIUM)); + + *fetc = *pformatetc; + + if (fRelease) + *pStgMed = *pmedium; + else + CopyMedium(pStgMed, pmedium, pformatetc); + + DataStorage storage; + + storage._format = fetc; + storage._medium = pStgMed; + + _storage.push_back(storage); + + return S_OK; +} + +void IDataObjectImpl::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc) +{ + switch(pMedSrc->tymed) + { + case TYMED_HGLOBAL: + pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal, pFmtSrc->cfFormat, 0); + break; + case TYMED_GDI: + pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap, pFmtSrc->cfFormat, 0); + break; + case TYMED_MFPICT: + pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict, pFmtSrc->cfFormat, 0); + break; + case TYMED_ENHMF: + pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile, pFmtSrc->cfFormat, 0); + break; + case TYMED_FILE: + pMedDest->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName, pFmtSrc->cfFormat, 0); + break; + case TYMED_ISTREAM: + pMedDest->pstm = pMedSrc->pstm; + pMedSrc->pstm->AddRef(); + break; + case TYMED_ISTORAGE: + pMedDest->pstg = pMedSrc->pstg; + pMedSrc->pstg->AddRef(); + break; + case TYMED_NULL: + default: + break; + } + pMedDest->tymed = pMedSrc->tymed; + pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease; +} + +STDMETHODIMP IDataObjectImpl::EnumFormatEtc( + /* [in] */ DWORD dwDirection, + /* [out] */ IEnumFORMATETC __RPC_FAR *__RPC_FAR *ppenumFormatEtc) +{ + if (ppenumFormatEtc == NULL) + return E_POINTER; + + *ppenumFormatEtc=NULL; + switch (dwDirection) + { + case DATADIR_GET: + *ppenumFormatEtc = new EnumFormatEtcImpl(_storage); + + if (!*ppenumFormatEtc) + return E_OUTOFMEMORY; + + (*ppenumFormatEtc)->AddRef(); + break; + + case DATADIR_SET: + default: + return E_NOTIMPL; + break; + } + + return S_OK; +} + +STDMETHODIMP IDataObjectImpl::DAdvise( + /* [in] */ FORMATETC __RPC_FAR *pformatetc, + /* [in] */ DWORD advf, + /* [unique][in] */ IAdviseSink __RPC_FAR *pAdvSink, + /* [out] */ DWORD __RPC_FAR *pdwConnection) +{ + return OLE_E_ADVISENOTSUPPORTED; +} + +STDMETHODIMP IDataObjectImpl::DUnadvise( + /* [in] */ DWORD dwConnection) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IDataObjectImpl::EnumDAdvise( + /* [out] */ IEnumSTATDATA __RPC_FAR *__RPC_FAR *ppenumAdvise) +{ + return OLE_E_ADVISENOTSUPPORTED; +} + +////////////////////////////////////////////////////////////////////// +// IDropSourceImpl Class +////////////////////////////////////////////////////////////////////// + +STDMETHODIMP IDropSourceImpl::QueryInterface(/* [in] */ REFIID riid, + /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) +{ + *ppvObject = NULL; + if (IID_IUnknown==riid || IID_IDropSource==riid) + *ppvObject=this; + + if (*ppvObject != NULL) + { + ((LPUNKNOWN)*ppvObject)->AddRef(); + return S_OK; + } + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) IDropSourceImpl::AddRef() +{ + return ++m_cRefCount; +} + +STDMETHODIMP_(ULONG) IDropSourceImpl::Release() +{ + long nTemp = --m_cRefCount; + + assert(nTemp >= 0); + + if (nTemp == 0) + delete this; + + return nTemp; +} + +STDMETHODIMP IDropSourceImpl::QueryContinueDrag( + /* [in] */ BOOL fEscapePressed, + /* [in] */ DWORD grfKeyState) +{ + if (fEscapePressed) + return DRAGDROP_S_CANCEL; + if (!(grfKeyState & (MK_LBUTTON|MK_RBUTTON))) + { + m_bDropped = true; + return DRAGDROP_S_DROP; + } + + return S_OK; + +} + +STDMETHODIMP IDropSourceImpl::GiveFeedback( + /* [in] */ DWORD dwEffect) +{ + return DRAGDROP_S_USEDEFAULTCURSORS; +} + +////////////////////////////////////////////////////////////////////// +// EnumFormatEtcImpl Class +////////////////////////////////////////////////////////////////////// + +EnumFormatEtcImpl::EnumFormatEtcImpl(const FormatArray& ArrFE) + : m_cRefCount(0), + m_iCur(0) +{ + for(FormatArray::const_iterator it=ArrFE.begin(); it!=ArrFE.end(); ++it) + m_pFmtEtc.push_back(*it); +} + +EnumFormatEtcImpl::EnumFormatEtcImpl(const StorageArray& ArrFE) + : m_cRefCount(0), + m_iCur(0) +{ + for(StorageArray::const_iterator it=ArrFE.begin(); it!=ArrFE.end(); ++it) + m_pFmtEtc.push_back(*it->_format); +} + +STDMETHODIMP EnumFormatEtcImpl::QueryInterface(REFIID refiid, void** ppv) +{ + *ppv = NULL; + if (IID_IUnknown==refiid || IID_IEnumFORMATETC==refiid) + *ppv=this; + + if (*ppv != NULL) + { + ((LPUNKNOWN)*ppv)->AddRef(); + return S_OK; + } + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) EnumFormatEtcImpl::AddRef(void) +{ + return ++m_cRefCount; +} + +STDMETHODIMP_(ULONG) EnumFormatEtcImpl::Release(void) +{ + long nTemp = --m_cRefCount; + + assert(nTemp >= 0); + + if (nTemp == 0) + delete this; + + return nTemp; +} + +STDMETHODIMP EnumFormatEtcImpl::Next( ULONG celt,LPFORMATETC lpFormatEtc, ULONG* pceltFetched) +{ + if (pceltFetched != NULL) + *pceltFetched=0; + + ULONG cReturn = celt; + + if (celt <= 0 || lpFormatEtc == NULL || m_iCur >= m_pFmtEtc.size()) + return S_FALSE; + + if (pceltFetched == NULL && celt != 1) // pceltFetched can be NULL only for 1 item request + return S_FALSE; + + while (m_iCur < m_pFmtEtc.size() && cReturn > 0) + { + *lpFormatEtc++ = m_pFmtEtc[m_iCur++]; + --cReturn; + } + if (pceltFetched != NULL) + *pceltFetched = celt - cReturn; + + return (cReturn == 0) ? S_OK : S_FALSE; +} + +STDMETHODIMP EnumFormatEtcImpl::Skip(ULONG celt) +{ + if ((m_iCur + int(celt)) >= m_pFmtEtc.size()) + return S_FALSE; + + m_iCur += celt; + return S_OK; +} + +STDMETHODIMP EnumFormatEtcImpl::Reset(void) +{ + m_iCur = 0; + return S_OK; +} + +STDMETHODIMP EnumFormatEtcImpl::Clone(IEnumFORMATETC** ppCloneEnumFormatEtc) +{ + if (ppCloneEnumFormatEtc == NULL) + return E_POINTER; + + EnumFormatEtcImpl* newEnum = new EnumFormatEtcImpl(m_pFmtEtc); + + if (!newEnum) + return E_OUTOFMEMORY; + + newEnum->AddRef(); + newEnum->m_iCur = m_iCur; + *ppCloneEnumFormatEtc = newEnum; + + return S_OK; +} + +////////////////////////////////////////////////////////////////////// +// IDropTargetImpl Class +////////////////////////////////////////////////////////////////////// +IDropTargetImpl::IDropTargetImpl(HWND hTargetWnd): + m_hTargetWnd(hTargetWnd), + m_cRefCount(0), m_bAllowDrop(false), + m_pDropTargetHelper(NULL), m_pSupportedFrmt(NULL) +{ + assert(m_hTargetWnd != NULL); + + if (FAILED(CoCreateInstance(CLSID_DragDropHelper,NULL,CLSCTX_INPROC_SERVER, + IID_IDropTargetHelper,(LPVOID*)&m_pDropTargetHelper))) + m_pDropTargetHelper = NULL; +} + +IDropTargetImpl::~IDropTargetImpl() +{ + if (m_pDropTargetHelper != NULL) + { + m_pDropTargetHelper->Release(); + m_pDropTargetHelper = NULL; + } +} + +HRESULT STDMETHODCALLTYPE IDropTargetImpl::QueryInterface( /* [in] */ REFIID riid, + /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) +{ + *ppvObject = NULL; + if (IID_IUnknown==riid || IID_IDropTarget==riid) + *ppvObject=this; + + if (*ppvObject != NULL) + { + ((LPUNKNOWN)*ppvObject)->AddRef(); + return S_OK; + } + return E_NOINTERFACE; +} + +ULONG STDMETHODCALLTYPE IDropTargetImpl::Release() +{ + long nTemp = --m_cRefCount; + + assert(nTemp >= 0); + + if (nTemp == 0) + delete this; + + return nTemp; +} + +bool IDropTargetImpl::QueryDrop(DWORD grfKeyState, LPDWORD pdwEffect) +{ + DWORD dwOKEffects = *pdwEffect; + + if (!m_bAllowDrop) + { + *pdwEffect = DROPEFFECT_NONE; + return false; + } + //CTRL+SHIFT -- DROPEFFECT_LINK + //CTRL -- DROPEFFECT_COPY + //SHIFT -- DROPEFFECT_MOVE + //no modifier -- DROPEFFECT_MOVE or whatever is allowed by src + *pdwEffect = (grfKeyState & MK_CONTROL) ? + ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY ): + ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_MOVE : DROPEFFECT_NONE ); + if (*pdwEffect == 0) + { + // No modifier keys used by user while dragging. + if (DROPEFFECT_COPY & dwOKEffects) + *pdwEffect = DROPEFFECT_COPY; + else if (DROPEFFECT_MOVE & dwOKEffects) + *pdwEffect = DROPEFFECT_MOVE; + else if (DROPEFFECT_LINK & dwOKEffects) + *pdwEffect = DROPEFFECT_LINK; + else + { + *pdwEffect = DROPEFFECT_NONE; + } + } + else + { + // Check if the drag source application allows the drop effect desired by user. + // The drag source specifies this in DoDragDrop + if (!(*pdwEffect & dwOKEffects)) + *pdwEffect = DROPEFFECT_NONE; + } + + return (DROPEFFECT_NONE == *pdwEffect)?false:true; +} + +HRESULT STDMETHODCALLTYPE IDropTargetImpl::DragEnter( + /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect) +{ + if (pDataObj == NULL) + return E_INVALIDARG; + + if (m_pDropTargetHelper) + m_pDropTargetHelper->DragEnter(m_hTargetWnd, pDataObj, (LPPOINT)&pt, *pdwEffect); + //IEnumFORMATETC* pEnum; + //pDataObj->EnumFormatEtc(DATADIR_GET,&pEnum); + //FORMATETC ftm; + //for() + //pEnum->Next(1,&ftm,0); + //pEnum->Release(); + m_pSupportedFrmt = NULL; + + for(FormatArray::iterator it=m_formatetc.begin(); it!=m_formatetc.end(); ++it) + { + m_bAllowDrop = (pDataObj->QueryGetData(&*it) == S_OK)? true: false; + + if (m_bAllowDrop) + { + m_pSupportedFrmt = &*it; + break; + } + } + + QueryDrop(grfKeyState, pdwEffect); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IDropTargetImpl::DragOver( + /* [in] */ DWORD grfKeyState, + /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect) +{ + if (m_pDropTargetHelper) + m_pDropTargetHelper->DragOver((LPPOINT)&pt, *pdwEffect); + QueryDrop(grfKeyState, pdwEffect); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IDropTargetImpl::DragLeave() +{ + if (m_pDropTargetHelper) + m_pDropTargetHelper->DragLeave(); + + m_bAllowDrop = false; + m_pSupportedFrmt = NULL; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IDropTargetImpl::Drop( + /* [unique][in] */ IDataObject __RPC_FAR *pDataObj, + /* [in] */ DWORD grfKeyState, /* [in] */ POINTL pt, + /* [out][in] */ DWORD __RPC_FAR *pdwEffect) +{ + if (pDataObj == NULL) + return E_INVALIDARG; + + if (m_pDropTargetHelper) + m_pDropTargetHelper->Drop(pDataObj, (LPPOINT)&pt, *pdwEffect); + + if (QueryDrop(grfKeyState, pdwEffect)) + { + if (m_bAllowDrop && m_pSupportedFrmt != NULL) + { + STGMEDIUM medium; + + if (pDataObj->GetData(m_pSupportedFrmt, &medium) == S_OK) + { + if (OnDrop(m_pSupportedFrmt, medium, pdwEffect)) //does derive class wants us to free medium? + ReleaseStgMedium(&medium); + } + } + } + + m_bAllowDrop = false; + *pdwEffect = DROPEFFECT_NONE; + m_pSupportedFrmt = NULL; + + return S_OK; +}