You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
418 lines
9.7 KiB
418 lines
9.7 KiB
/**************************************************************************
|
|
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);
|
|
}
|
|
}
|
|
|