mirror of https://github.com/tongzx/nt5src
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.
468 lines
11 KiB
468 lines
11 KiB
//
|
|
// DropTarget.cpp
|
|
//
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
|
|
#include "foldinc.h" // Standard shell\folder includes
|
|
#include "droptarget.h"
|
|
|
|
CDropTarget::CDropTarget(IShellFolder *psfParent)
|
|
{
|
|
m_uiRefCount = 1;
|
|
|
|
m_psfParent = psfParent;
|
|
if(m_psfParent)
|
|
{
|
|
m_psfParent->AddRef();
|
|
}
|
|
|
|
m_bAcceptFmt = FALSE;
|
|
// TODO : Register your own clipboard format here
|
|
|
|
m_cfPrivatePidlData = static_cast<CLIPFORMAT>(RegisterClipboardFormat(CFSTR_SHELLIDLIST));
|
|
m_cfPrivateFileData = CF_HDROP;
|
|
}
|
|
|
|
CDropTarget::~CDropTarget()
|
|
{
|
|
if(m_psfParent)
|
|
{
|
|
m_psfParent->Release();
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// IUnknown Implementation
|
|
//
|
|
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;
|
|
}
|
|
|
|
STDMETHODIMP_(DWORD) CDropTarget::AddRef(VOID)
|
|
{
|
|
return ++m_uiRefCount;
|
|
}
|
|
|
|
STDMETHODIMP_(DWORD) CDropTarget::Release(VOID)
|
|
{
|
|
if(--m_uiRefCount == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return m_uiRefCount;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// IDropTarget implemenatation
|
|
//
|
|
STDMETHODIMP CDropTarget::DragEnter( LPDATAOBJECT pDataObj,
|
|
DWORD dwKeyState,
|
|
POINTL pt,
|
|
LPDWORD pdwEffect)
|
|
{
|
|
// TODO : Handle DragEnter here
|
|
FORMATETC fmtetc;
|
|
|
|
fmtetc.cfFormat = m_cfPrivatePidlData;
|
|
fmtetc.ptd = NULL;
|
|
fmtetc.dwAspect = DVASPECT_CONTENT;
|
|
fmtetc.lindex = -1;
|
|
fmtetc.tymed = TYMED_HGLOBAL;
|
|
|
|
// QueryGetData for pDataObject for our format
|
|
m_bAcceptFmt = (S_OK == pDataObj->QueryGetData(&fmtetc)) ? TRUE : FALSE;
|
|
|
|
if (m_bAcceptFmt)
|
|
{
|
|
if (queryDrop(dwKeyState, pdwEffect))
|
|
{
|
|
HRESULT hr;
|
|
FORMATETC fe;
|
|
STGMEDIUM stgmed;
|
|
|
|
fe.cfFormat = m_cfPrivatePidlData;
|
|
fe.ptd = NULL;
|
|
fe.dwAspect = DVASPECT_CONTENT;
|
|
fe.lindex = -1;
|
|
fe.tymed = TYMED_HGLOBAL;
|
|
|
|
// Get the storage medium from the data object.
|
|
hr = pDataObj->GetData(&fe, &stgmed);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_bAcceptFmt = CanDropPidl(stgmed.hGlobal);
|
|
}
|
|
else
|
|
{
|
|
m_bAcceptFmt = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_bAcceptFmt = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!m_bAcceptFmt)
|
|
{
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
}
|
|
|
|
return m_bAcceptFmt ? E_FAIL : E_FAIL;
|
|
}
|
|
|
|
STDMETHODIMP CDropTarget::DragOver(DWORD dwKeyState, POINTL pt, LPDWORD pdwEffect)
|
|
{
|
|
BOOL bRet = queryDrop(dwKeyState, pdwEffect);
|
|
|
|
return bRet ? E_FAIL : E_FAIL;
|
|
}
|
|
|
|
STDMETHODIMP CDropTarget::DragLeave(VOID)
|
|
{
|
|
m_bAcceptFmt = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CDropTarget::Drop(LPDATAOBJECT pDataObj,
|
|
DWORD dwKeyState,
|
|
POINTL pt,
|
|
LPDWORD pdwEffect)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
if (queryDrop(dwKeyState, pdwEffect))
|
|
{
|
|
FORMATETC fe;
|
|
STGMEDIUM stgmed;
|
|
|
|
fe.cfFormat = m_cfPrivatePidlData;
|
|
fe.ptd = NULL;
|
|
fe.dwAspect = DVASPECT_CONTENT;
|
|
fe.lindex = -1;
|
|
fe.tymed = TYMED_HGLOBAL;
|
|
|
|
// Get the storage medium from the data object.
|
|
hr = pDataObj->GetData(&fe, &stgmed);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BOOL bRet = doPIDLDrop(stgmed.hGlobal, DROPEFFECT_MOVE == *pdwEffect);
|
|
|
|
//release the STGMEDIUM
|
|
ReleaseStgMedium(&stgmed);
|
|
|
|
return bRet ? S_OK : E_FAIL;
|
|
}
|
|
}
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
return hr;
|
|
}
|
|
|
|
// Private helper functions:
|
|
// TODO : Modify to suit your needs
|
|
BOOL CDropTarget::queryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
|
|
{
|
|
DWORD dwOKEffects = *pdwEffect;
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
if (m_bAcceptFmt)
|
|
{
|
|
*pdwEffect = getDropEffectFromKeyState(dwKeyState);
|
|
|
|
if(DROPEFFECT_LINK == *pdwEffect)
|
|
{
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
}
|
|
|
|
if(*pdwEffect & dwOKEffects)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// TODO : Modify to suit your needs
|
|
DWORD CDropTarget::getDropEffectFromKeyState(DWORD dwKeyState)
|
|
{
|
|
DWORD dwDropEffect = DROPEFFECT_MOVE;
|
|
|
|
if(dwKeyState & MK_CONTROL)
|
|
{
|
|
if(dwKeyState & MK_SHIFT)
|
|
{
|
|
dwDropEffect = DROPEFFECT_LINK;
|
|
}
|
|
else
|
|
{
|
|
dwDropEffect = DROPEFFECT_COPY;
|
|
}
|
|
}
|
|
return dwDropEffect;
|
|
}
|
|
|
|
#define HIDA_GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
|
|
#define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
|
|
|
|
LPCITEMIDLIST IDA_GetIDListPtr(LPIDA pida, UINT i)
|
|
{
|
|
if (NULL == pida)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (i == (UINT)-1 || i < pida->cidl)
|
|
{
|
|
return HIDA_GetPIDLItem(pida, i);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// in:
|
|
// psf OPTIONAL, if NULL assume psfDesktop
|
|
// pidl to bind to from psfParent
|
|
// pbc bind context
|
|
|
|
STDAPI SHBindToObjectEx(IShellFolder *psf, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvOut)
|
|
{
|
|
HRESULT hr;
|
|
IShellFolder *psfRelease;
|
|
|
|
if (!psf)
|
|
{
|
|
SHGetDesktopFolder(&psf);
|
|
psfRelease = psf;
|
|
}
|
|
else
|
|
{
|
|
psfRelease = NULL;
|
|
}
|
|
|
|
if (psf)
|
|
{
|
|
if (!pidl || ILIsEmpty(pidl))
|
|
{
|
|
hr = psf->QueryInterface(riid, ppvOut);
|
|
}
|
|
else
|
|
{
|
|
hr = psf->BindToObject(pidl, pbc, riid, ppvOut);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*ppvOut = NULL;
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
if (psfRelease)
|
|
{
|
|
psfRelease->Release();
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && (*ppvOut == NULL))
|
|
{
|
|
// Some shell extensions (eg WS_FTP) will return success and a null out pointer
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDAPI SHBindToObject(IShellFolder *psf, REFIID riid, LPCITEMIDLIST pidl, void **ppvOut)
|
|
{
|
|
// NOTE: callers should use SHBindToObjectEx!!!
|
|
return SHBindToObjectEx(psf, pidl, NULL, riid, ppvOut);
|
|
}
|
|
|
|
BOOL CDropTarget::CanDropPidl(HGLOBAL hMem)
|
|
{
|
|
CONFOLDENTRY cfeEmpty;
|
|
return CanDropPidl(hMem, cfeEmpty);
|
|
}
|
|
|
|
BOOL CDropTarget::CanDropPidl(HGLOBAL hMem, CONFOLDENTRY& cfe)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
USES_CONVERSION;
|
|
if(hMem)
|
|
{
|
|
LPIDA pida = (LPIDA)GlobalLock(hMem);
|
|
if (pida)
|
|
{
|
|
if (pida->cidl != 1)
|
|
{
|
|
return FALSE; // Don't support multiple files
|
|
}
|
|
|
|
HRESULT hr;
|
|
IShellFolder *psf;
|
|
|
|
LPCITEMIDLIST pIdList = IDA_GetIDListPtr(pida, (UINT)-1);
|
|
hr = SHBindToObject(NULL, IID_IShellFolder, pIdList, reinterpret_cast<LPVOID *>(&psf) );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
for (UINT i = 0; i < pida->cidl; i++)
|
|
{
|
|
LPCITEMIDLIST pidlLast = IDA_GetIDListPtr(pida, i);
|
|
IShellLink *psl;
|
|
hr = psf->GetUIObjectOf(NULL, 1, &pidlLast, IID_IShellLink, NULL, reinterpret_cast<LPVOID *>(&psl) );
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPITEMIDLIST pItemIdList = NULL;
|
|
hr = psl->GetIDList(&pItemIdList);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pItemIdList = ILFindLastIDPriv(pItemIdList); // Desktop
|
|
if (pItemIdList)
|
|
{
|
|
PCONFOLDPIDL cfp;
|
|
hr = cfp.InitializeFromItemIDList(pItemIdList);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = cfp.ConvertToConFoldEntry(cfe);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if ( !(cfe.GetCharacteristics() & NCCF_BRANDED) &&
|
|
((cfe.GetNetConMediaType() == NCM_PHONE) || (cfe.GetNetConMediaType() == NCM_TUNNEL)) )
|
|
{
|
|
fSuccess = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
psl->Release();
|
|
}
|
|
}
|
|
}
|
|
GlobalUnlock(hMem);
|
|
}
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
#include "nccom.h"
|
|
#include "..\\dun\\dunimport.h"
|
|
|
|
HRESULT HrGetNewConnection (INetConnection** ppCon, const CONFOLDENTRY& cfe)
|
|
{
|
|
static const CLSID CLSID_DialupConnection =
|
|
{0xBA126AD7,0x2166,0x11D1,{0xB1,0xD0,0x00,0x80,0x5F,0xC1,0x27,0x0E}};
|
|
|
|
HRESULT hr;
|
|
|
|
// Validate parameters.
|
|
//
|
|
if (!ppCon)
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
else if (!cfe.GetName())
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
// Create an uninitialized dialup connection object.
|
|
// Ask for the INetRasConnection interface so we can
|
|
// initialize it.
|
|
//
|
|
INetRasConnection* pRasCon;
|
|
|
|
hr = HrCreateInstance(
|
|
CLSID_DialupConnection,
|
|
CLSCTX_LOCAL_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
|
|
&pRasCon);
|
|
|
|
TraceHr(ttidError, FAL, hr, FALSE, "HrCreateInstance");
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
NcSetProxyBlanket (pRasCon);
|
|
|
|
tstring strPhoneBook;
|
|
hr = HrGetPhoneBookFile(strPhoneBook);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
RASENTRY RasEntry = {0};
|
|
wcsncpy(RasEntry.szLocalPhoneNumber, cfe.GetPhoneOrHostAddress(), RAS_MaxPhoneNumber);
|
|
RasEntry.dwfOptions |= RASEO_PreviewUserPw;
|
|
RasEntry.dwSize = sizeof(RASENTRY);
|
|
|
|
if (cfe.GetNetConMediaType() == NCM_PHONE)
|
|
{
|
|
lstrcpyW(RasEntry.szDeviceType, RASDT_Modem);
|
|
}
|
|
if (cfe.GetNetConMediaType() == NCM_TUNNEL)
|
|
{
|
|
lstrcpyW(RasEntry.szDeviceType, RASDT_Vpn);
|
|
}
|
|
lstrcpyW(RasEntry.szDeviceName, L"Standard Modem");
|
|
RasEntry.dwFramingProtocol = RASFP_Ras;
|
|
|
|
DWORD dwRet = RasSetEntryProperties(strPhoneBook.c_str(),
|
|
cfe.GetName(),
|
|
&RasEntry,
|
|
sizeof(RASENTRY),
|
|
NULL,
|
|
0);
|
|
|
|
hr = HRESULT_FROM_WIN32(dwRet);
|
|
Assert(SUCCEEDED(hr));
|
|
}
|
|
|
|
ReleaseObj (pRasCon);
|
|
}
|
|
}
|
|
TraceError ("CRasUiBase::HrGetNewConnection", hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
BOOL CDropTarget::doPIDLDrop(HGLOBAL hMem, BOOL bCut)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
CONFOLDENTRY cfe;
|
|
|
|
if (CanDropPidl(hMem, cfe))
|
|
{
|
|
ConnListEntry cle;
|
|
HRESULT hr = g_ccl.HrFindConnectionByGuid(&cfe.GetGuidID(), cle);
|
|
if (S_FALSE == hr)
|
|
{
|
|
INetConnection *pInetcon;
|
|
HrGetNewConnection(&pInetcon, cfe);
|
|
}
|
|
else
|
|
{
|
|
::MessageBox(NULL, L"This item already exists in the Network Connections folder", L"Error", MB_OK);
|
|
}
|
|
fSuccess = TRUE;
|
|
}
|
|
return fSuccess;
|
|
}
|