/************************************************************************** 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. Copyright 1998 Microsoft Corporation. All Rights Reserved. **************************************************************************/ /************************************************************************** File: DropTgt.cpp Description: Implements CDropTarget. **************************************************************************/ /************************************************************************** #include statements **************************************************************************/ #include "DropTgt.h" #include "Utility.h" /************************************************************************** CDropTarget::CDropTarget() **************************************************************************/ CDropTarget::CDropTarget(CShellFolder *psfParent) { g_DllRefCount++; m_psfParent = psfParent; if(m_psfParent) m_psfParent->AddRef(); else { delete this; return; } m_pPidlMgr = new CPidlMgr(); if(!m_pPidlMgr) { delete this; return; } SHGetMalloc(&m_pMalloc); if(!m_pMalloc) { delete this; return; } m_ObjRefCount = 1; m_fAcceptFmt = FALSE; m_cfPrivateData = RegisterClipboardFormat(CFSTR_SAMPVIEWDATA); } /************************************************************************** CDropTarget::~CDropTarget() **************************************************************************/ CDropTarget::~CDropTarget() { if(m_psfParent) m_psfParent->Release(); if(m_pPidlMgr) delete m_pPidlMgr; if(m_pMalloc) m_pMalloc->Release(); g_DllRefCount--; } /////////////////////////////////////////////////////////////////////////// // // IUnknown Implementation // /************************************************************************** CDropTarget::QueryInterface() **************************************************************************/ STDMETHODIMP CDropTarget::QueryInterface(REFIID riid, LPVOID *ppReturn) { *ppReturn = NULL; //IUnknown if(IsEqualIID(riid, IID_IUnknown)) { *ppReturn = this; } //IDropTarget else if(IsEqualIID(riid, IID_IDropTarget)) { *ppReturn = (IDropTarget*)this; } if(*ppReturn) { (*(LPUNKNOWN*)ppReturn)->AddRef(); return S_OK; } return E_NOINTERFACE; } /************************************************************************** CDropTarget::AddRef() **************************************************************************/ STDMETHODIMP_(DWORD) CDropTarget::AddRef(VOID) { return ++m_ObjRefCount; } /************************************************************************** CDropTarget::Release() **************************************************************************/ STDMETHODIMP_(DWORD) CDropTarget::Release(VOID) { if(--m_ObjRefCount == 0) { delete this; return 0; } return m_ObjRefCount; } /////////////////////////////////////////////////////////////////////////// // // IDropTarget Implementation // /************************************************************************** CDropTarget::DragEnter() **************************************************************************/ STDMETHODIMP CDropTarget::DragEnter( LPDATAOBJECT pDataObj, DWORD dwKeyState, POINTL pt, LPDWORD pdwEffect) { FORMATETC fmtetc; fmtetc.cfFormat = m_cfPrivateData; fmtetc.ptd = NULL; fmtetc.dwAspect = DVASPECT_CONTENT; fmtetc.lindex = -1; fmtetc.tymed = TYMED_HGLOBAL; //does the drag source provide our data type? m_fAcceptFmt = (S_OK == pDataObj->QueryGetData(&fmtetc)) ? TRUE : FALSE; QueryDrop(dwKeyState, pdwEffect); return S_OK; } /************************************************************************** CDropTarget::DragOver() **************************************************************************/ STDMETHODIMP CDropTarget::DragOver(DWORD dwKeyState, POINTL pt, LPDWORD pdwEffect) { QueryDrop(dwKeyState, pdwEffect); return S_OK; } /************************************************************************** CDropTarget::DragLeave() **************************************************************************/ STDMETHODIMP CDropTarget::DragLeave(VOID) { m_fAcceptFmt = FALSE; return S_OK; } /************************************************************************** CDropTarget::Drop() **************************************************************************/ STDMETHODIMP CDropTarget::Drop( LPDATAOBJECT pDataObj, DWORD dwKeyState, POINTL pt, LPDWORD pdwEffect) { HRESULT hr = E_FAIL; if(QueryDrop(dwKeyState, pdwEffect)) { FORMATETC fmtetc; STGMEDIUM medium; fmtetc.cfFormat = m_cfPrivateData; fmtetc.ptd = NULL; fmtetc.dwAspect = DVASPECT_CONTENT; fmtetc.lindex = -1; fmtetc.tymed = TYMED_HGLOBAL; //The user has dropped on us. Get the data from the data object. hr = pDataObj->GetData(&fmtetc, &medium); if(SUCCEEDED(hr)) { DoDrop(medium.hGlobal, DROPEFFECT_MOVE == *pdwEffect); //release the STGMEDIUM ReleaseStgMedium(&medium); return S_OK; } } *pdwEffect = DROPEFFECT_NONE; return hr; } /************************************************************************** CDropTarget::QueryDrop() **************************************************************************/ BOOL CDropTarget::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect) { DWORD dwOKEffects = *pdwEffect; *pdwEffect = DROPEFFECT_NONE; if(m_fAcceptFmt) { *pdwEffect = GetDropEffectFromKeyState(dwKeyState); //we don't accept links if(DROPEFFECT_LINK == *pdwEffect) *pdwEffect = DROPEFFECT_NONE; /* Check if the drag source application allows the drop effect desired by the user. The drag source specifies this in DoDragDrop. */ if(*pdwEffect & dwOKEffects) return TRUE; } return FALSE; } /************************************************************************** CDropTarget::GetDropEffectFromKeyState() **************************************************************************/ DWORD CDropTarget::GetDropEffectFromKeyState(DWORD dwKeyState) { //move is the default DWORD dwDropEffect = DROPEFFECT_MOVE; if(dwKeyState & MK_CONTROL) { if(dwKeyState & MK_SHIFT) { dwDropEffect = DROPEFFECT_LINK; } else { dwDropEffect = DROPEFFECT_COPY; } } return dwDropEffect; } /************************************************************************** CDropTarget::DoDrop() **************************************************************************/ BOOL CDropTarget::DoDrop(HGLOBAL hMem, BOOL fCut) { BOOL fSuccess = FALSE; if(hMem) { LPPRIVCLIPDATA pData = (LPPRIVCLIPDATA)GlobalLock(hMem); if(pData) { CShellFolder *psfFrom = NULL; IShellFolder *psfDesktop; LPITEMIDLIST pidl; pidl = (LPITEMIDLIST)((LPBYTE)(pData) + pData->aoffset[0]); /* This is a fully qualified PIDL, so use the desktop folder to get the IShellFolder for this folder. */ SHGetDesktopFolder(&psfDesktop); if(psfDesktop) { psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfFrom); psfDesktop->Release(); } if(psfFrom) { LPITEMIDLIST *aPidls; //allocate an array of PIDLS aPidls = AllocPidlTable(pData->cidl - 1); if(aPidls) { UINT i; //fill in the PIDL array for(i = 0; i < pData->cidl - 1; i++) { aPidls[i] = m_pPidlMgr->Copy((LPITEMIDLIST)((LPBYTE)(pData) + pData->aoffset[i + 1])); } if(SUCCEEDED(m_psfParent->CopyItems(psfFrom, aPidls, pData->cidl - 1))) { fSuccess = TRUE; if(fCut) { psfFrom->DeleteItems(aPidls, pData->cidl - 1); } } FreePidlTable(aPidls); } psfFrom->Release(); } GlobalUnlock(hMem); } } return fSuccess; } /************************************************************************** CDropTarget::AllocPidlTable() **************************************************************************/ LPITEMIDLIST* CDropTarget::AllocPidlTable(DWORD dwEntries) { LPITEMIDLIST *aPidls; dwEntries++; aPidls = (LPITEMIDLIST*)m_pMalloc->Alloc(dwEntries * sizeof(LPITEMIDLIST)); if(aPidls) { //set all of the entries to NULL ZeroMemory(aPidls, dwEntries * sizeof(LPITEMIDLIST)); } return aPidls; } /************************************************************************** CDropTarget::FreePidlTable() **************************************************************************/ VOID CDropTarget::FreePidlTable(LPITEMIDLIST *aPidls) { if(aPidls && m_pPidlMgr) { UINT i; for(i = 0; aPidls[i]; i++) m_pPidlMgr->Delete(aPidls[i]); m_pMalloc->Free(aPidls); } }