#include "shellprv.h" #include "duiview.h" #include "duidrag.h" CDUIDropTarget::CDUIDropTarget() { _cRef = 1; _pDT = NULL; _pNextDT = NULL; } CDUIDropTarget::~CDUIDropTarget() { _Cleanup(); } HRESULT CDUIDropTarget::QueryInterface (REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CDUIDropTarget, IDropTarget), { 0 }, }; return QISearch(this, qit, riid, ppv); } ULONG CDUIDropTarget::AddRef (void) { return ++_cRef; } ULONG CDUIDropTarget::Release (void) { if (--_cRef == 0) { delete this; return 0; } return _cRef; } // Called by duser / directui to get the IDropTarget interface for the element // the mouse just moved over. It is important to understand the sequencing // calls. Initialize is called BEFORE DragLeave is called on the previous element's // IDropTarget, so we can't switch out _pDT right away. Instead, we'll store the // new IDropTarget in _pNextDT and then in DragEnter, we'll move it over to _pDT. // // The sequence looks like this: // // Initialize() for first element (bumps ref count to 2) // DragEnter // DragMove // Initialize() for second element (bumps ref count to 3) // DragLeave for first element // Release for first element (decrements ref count to 2) // DragEnter for second element HRESULT CDUIDropTarget::Initialize (LPITEMIDLIST pidl, HWND hWnd, IDropTarget **pdt) { ASSERT(_pNextDT == NULL); if (pidl) { SHGetUIObjectFromFullPIDL(pidl, hWnd, IID_PPV_ARG(IDropTarget, &_pNextDT)); } QueryInterface (IID_PPV_ARG(IDropTarget, pdt)); return S_OK; } VOID CDUIDropTarget::_Cleanup () { if (_pDT) { _pDT->Release(); _pDT = NULL; } } STDMETHODIMP CDUIDropTarget::DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect) { if ((_pDT != _pNextDT) || (_cRef == 2)) { _pDT = _pNextDT; _pNextDT = NULL; if (_pDT) { _pDT->DragEnter (pDataObj, grfKeyState, ptl, pdwEffect); } else { *pdwEffect = DROPEFFECT_NONE; } POINT pt; GetCursorPos(&pt); DAD_DragEnterEx2 (NULL, pt, pDataObj); } return S_OK; } STDMETHODIMP CDUIDropTarget::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect) { if (_pDT) { _pDT->DragOver (grfKeyState, ptl, pdwEffect); } else { *pdwEffect = DROPEFFECT_NONE; } POINT pt; GetCursorPos(&pt); DAD_DragMove (pt); return S_OK; } STDMETHODIMP CDUIDropTarget::DragLeave(void) { if (_pDT || (_cRef == 2)) { if (_pDT) { _pDT->DragLeave (); } DAD_DragLeave(); _Cleanup(); } return S_OK; } STDMETHODIMP CDUIDropTarget::Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect) { POINT pt = {ptl.x, ptl.y}; HRESULT hr = S_OK; if (_pDT) { hr = _pDT->Drop (pDataObj, grfKeyState, ptl, pdwEffect); } return hr; }