// // 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(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(&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(&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; }