|
|
#include "private.h"
#include "offl_cpp.h"
#include "subsmgrp.h"
HRESULT _GetURLData(IDataObject *, int, TCHAR *, TCHAR *); HRESULT _ConvertHDROPData(IDataObject *, BOOL); HRESULT ScheduleDefault(LPCTSTR, LPCTSTR);
#define CITBDTYPE_HDROP 1
#define CITBDTYPE_URL 2
#define CITBDTYPE_TEXT 3
//
// Constructor
//
COfflineDropTarget::COfflineDropTarget(HWND hwndParent) { m_cRefs = 1; m_hwndParent = hwndParent; m_pDataObj = NULL; m_grfKeyStateLast = 0; m_fHasHDROP = FALSE; m_fHasSHELLURL = FALSE; m_fHasTEXT = FALSE; m_dwEffectLastReturned = 0;
DllAddRef(); }
//
// Destructor
//
COfflineDropTarget::~COfflineDropTarget() { DllRelease(); }
//
// QueryInterface
//
STDMETHODIMP COfflineDropTarget::QueryInterface(REFIID riid, LPVOID *ppv) { HRESULT hr = E_NOINTERFACE;
*ppv = NULL;
// Any interface on this object is the object pointer
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDropTarget)) { *ppv = (LPDROPTARGET)this;
AddRef();
hr = NOERROR; }
return hr; }
//
// AddRef
//
STDMETHODIMP_(ULONG) COfflineDropTarget::AddRef() { return ++m_cRefs; }
//
// Release
//
STDMETHODIMP_(ULONG) COfflineDropTarget::Release() { if (0L != --m_cRefs) { return m_cRefs; }
delete this;
return 0L; }
//
// DragEnter
//
STDMETHODIMP COfflineDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) { // Release any old data object we might have
// TraceMsg(TF_SUBSFOLDER, TEXT("odt - DragEnter"));
if (m_pDataObj) { m_pDataObj->Release(); }
m_grfKeyStateLast = grfKeyState; m_pDataObj = pDataObj;
//
// See if we will be able to get CF_HDROP from this guy
//
if (pDataObj) { pDataObj->AddRef(); TCHAR url[INTERNET_MAX_URL_LENGTH], name[MAX_NAME_QUICKLINK]; FORMATETC fe = {(CLIPFORMAT) RegisterClipboardFormat(CFSTR_SHELLURL), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
m_fHasSHELLURL = m_fHasHDROP = m_fHasTEXT = FALSE; if (NOERROR == pDataObj->QueryGetData(&fe)) { TraceMsg(TF_SUBSFOLDER, "odt - DragEnter : SHELLURL!"); m_fHasSHELLURL = (NOERROR == _GetURLData(pDataObj,CITBDTYPE_URL,url,name)); } if (fe.cfFormat = CF_HDROP, NOERROR == pDataObj->QueryGetData(&fe)) { TraceMsg(TF_SUBSFOLDER, "odt - DragEnter : HDROP!"); m_fHasHDROP = (NOERROR == _ConvertHDROPData(pDataObj, FALSE)); } if (fe.cfFormat = CF_TEXT, NOERROR == pDataObj->QueryGetData(&fe)) { TraceMsg(TF_SUBSFOLDER, "odt - DragEnter : TEXT!"); m_fHasTEXT = (NOERROR == _GetURLData(pDataObj,CITBDTYPE_TEXT,url,name)); } }
// Save the drop effect
if (pdwEffect) { *pdwEffect = m_dwEffectLastReturned = GetDropEffect(pdwEffect); }
return S_OK; }
//
// GetDropEffect
//
DWORD COfflineDropTarget::GetDropEffect(LPDWORD pdwEffect) { ASSERT(pdwEffect);
if (m_fHasSHELLURL || m_fHasTEXT) { return *pdwEffect & (DROPEFFECT_COPY | DROPEFFECT_LINK); } else if (m_fHasHDROP) { return *pdwEffect & (DROPEFFECT_COPY ); } else { return DROPEFFECT_NONE; } }
//
// DragOver
//
STDMETHODIMP COfflineDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) { // TraceMsg(TF_SUBSFOLDER, TEXT("odt - DragOver"));
if (m_grfKeyStateLast == grfKeyState) { // Return the effect we saved at dragenter time
if (*pdwEffect) { *pdwEffect = m_dwEffectLastReturned; } } else { if (*pdwEffect) { *pdwEffect = m_dwEffectLastReturned = GetDropEffect(pdwEffect); } }
m_grfKeyStateLast = grfKeyState;
return S_OK; }
//
// DragLeave
//
STDMETHODIMP COfflineDropTarget::DragLeave() { // TraceMsg(TF_SUBSFOLDER, TEXT("odt - DragLeave"));
if (m_pDataObj) { m_pDataObj->Release(); m_pDataObj = NULL; }
return S_OK; }
//
// Drop
//
STDMETHODIMP COfflineDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) { // UINT idCmd; // Choice from drop popup menu
HRESULT hr = S_OK; //
// Take the new data object, since OLE can give us a different one than
// it did in DragEnter
//
// TraceMsg(TF_SUBSFOLDER, TEXT("odt - Drop"));
if (m_pDataObj) { m_pDataObj->Release(); } m_pDataObj = pDataObj; if (pDataObj) { pDataObj->AddRef(); }
// If the dataobject doesn't have an HDROP, its not much good to us
*pdwEffect &= DROPEFFECT_COPY|DROPEFFECT_LINK; if (!(*pdwEffect)) { DragLeave(); return S_OK; }
hr = E_NOINTERFACE; if (m_fHasHDROP) hr = _ConvertHDROPData(pDataObj, TRUE); else { TCHAR url[INTERNET_MAX_URL_LENGTH], name[MAX_NAME_QUICKLINK]; if (m_fHasSHELLURL) hr = _GetURLData(pDataObj, CITBDTYPE_URL, url, name); if (FAILED(hr) && m_fHasTEXT) hr = _GetURLData(pDataObj, CITBDTYPE_TEXT, url, name); if (SUCCEEDED(hr)) { TraceMsg(TF_SUBSFOLDER, "URL: %s, Name: %s", url, name); hr = ScheduleDefault(url, name); } }
if (FAILED(hr)) { TraceMsg(TF_SUBSFOLDER, "Couldn't DROP"); }
DragLeave(); return hr; }
HRESULT _CLSIDFromExtension( LPCTSTR pszExt, CLSID *pclsid) { TCHAR szProgID[80]; long cb = SIZEOF(szProgID); if (RegQueryValue(HKEY_CLASSES_ROOT, pszExt, szProgID, &cb) == ERROR_SUCCESS) { TCHAR szCLSID[80]; StrCatN(szProgID, TEXT("\\CLSID"), ARRAYSIZE(szProgID)); cb = SIZEOF(szCLSID);
if (RegQueryValue(HKEY_CLASSES_ROOT, szProgID, szCLSID, &cb) == ERROR_SUCCESS) { // FEATURE (scotth): call shell32's SHCLSIDFromString once it
// exports A/W versions. This would clean this
// up.
#ifdef UNICODE
return CLSIDFromString(szCLSID, pclsid); #else
WCHAR wszCLSID[80]; MultiByteToWideChar(CP_ACP, 0, szCLSID, -1, wszCLSID, ARRAYSIZE(wszCLSID)); return CLSIDFromString(wszCLSID, pclsid); #endif
} } return E_FAIL; }
// get the target of a shortcut. this uses IShellLink which
// Internet Shortcuts (.URL) and Shell Shortcuts (.LNK) support so
// it should work generally
//
HRESULT _GetURLTarget(LPCTSTR pszPath, LPTSTR pszTarget, UINT cch) { IShellLink *psl; HRESULT hr = E_FAIL; CLSID clsid;
if (FAILED(_CLSIDFromExtension(PathFindExtension(pszPath), &clsid))) clsid = CLSID_ShellLink; // assume it's a shell link
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&psl);
if (SUCCEEDED(hr)) { IPersistFile *ppf;
hr = psl->QueryInterface(IID_IPersistFile, (void **)&ppf); if (SUCCEEDED(hr)) { #ifdef UNICODE
hr = ppf->Load(pszPath, 0); #else
WCHAR wszPath[MAX_PATH]; MultiByteToWideChar(CP_ACP, 0, pszPath, -1, wszPath, ARRAYSIZE(wszPath));
hr = ppf->Load (wszPath, 0); #endif
ppf->Release(); } if (SUCCEEDED(hr)) { IUniformResourceLocator * purl;
hr = psl->QueryInterface(IID_IUniformResourceLocator,(void**)&purl); if (SUCCEEDED(hr)) purl->Release(); } if (SUCCEEDED(hr)) hr = psl->GetPath(pszTarget, cch, NULL, SLGP_UNCPRIORITY); psl->Release(); } return hr; }
HRESULT _ConvertHDROPData(IDataObject *pdtobj, BOOL bSubscribe) { HRESULT hRes = NOERROR; STGMEDIUM stgmedium; FORMATETC formatetc; TCHAR url[INTERNET_MAX_URL_LENGTH]; TCHAR name[MAX_NAME_QUICKLINK];
name[0] = 0; url[0] = 0;
formatetc.cfFormat = CF_HDROP; formatetc.ptd = NULL; formatetc.dwAspect = DVASPECT_CONTENT; formatetc.lindex = -1; formatetc.tymed = TYMED_HGLOBAL;
// Get the parse string
hRes = pdtobj->GetData(&formatetc, &stgmedium); if (SUCCEEDED(hRes)) { LPTSTR pszURLData = (LPTSTR)GlobalLock(stgmedium.hGlobal); if (pszURLData) { TCHAR szPath[MAX_PATH]; SHFILEINFO sfi; int cFiles, i; HDROP hDrop = (HDROP)stgmedium.hGlobal;
hRes = S_FALSE; cFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); for (i = 0; i < cFiles; i ++) { DragQueryFile(hDrop, i, szPath, ARRAYSIZE(szPath));
// defaults...
StrCpyN(name, szPath, MAX_NAME_QUICKLINK);
if (SHGetFileInfo(szPath, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME)) StrCpyN(name, sfi.szDisplayName, MAX_NAME_QUICKLINK);
if (SHGetFileInfo(szPath, 0, &sfi, sizeof(sfi),SHGFI_ATTRIBUTES) && (sfi.dwAttributes & SFGAO_LINK)) { if (SUCCEEDED(_GetURLTarget(szPath, url, INTERNET_MAX_URL_LENGTH))) { TraceMsg(TF_SUBSFOLDER, "URL: %s, Name: %s", url, name); // If we just want to see whether there is some urls
// here, we can break now.
if (!bSubscribe) { if ((IsHTTPPrefixed(url)) && (!SHRestricted2(REST_NoAddingSubscriptions, url, 0))) { hRes = S_OK; } break; } hRes = ScheduleDefault(url, name); } } } GlobalUnlock(stgmedium.hGlobal); if (bSubscribe) hRes = S_OK; } else hRes = S_FALSE;
ReleaseStgMedium(&stgmedium); } return hRes; } // Takes a variety of inputs and returns a string for drop targets.
// szUrl: the URL
// szName: the name (for quicklinks and the confo dialog boxes)
// returns: NOERROR if succeeded
//
HRESULT _GetURLData(IDataObject *pdtobj, int iDropType, TCHAR *pszUrl, TCHAR *pszName) { HRESULT hRes = NOERROR; STGMEDIUM stgmedium; FORMATETC formatetc;
*pszName = 0; *pszUrl = 0;
switch (iDropType) { case CITBDTYPE_URL: formatetc.cfFormat = (CLIPFORMAT) RegisterClipboardFormat(CFSTR_SHELLURL); break; case CITBDTYPE_TEXT: formatetc.cfFormat = CF_TEXT; break; default: return E_UNEXPECTED; } formatetc.ptd = NULL; formatetc.dwAspect = DVASPECT_CONTENT; formatetc.lindex = -1; formatetc.tymed = TYMED_HGLOBAL;
// Get the parse string
hRes = pdtobj->GetData(&formatetc, &stgmedium); if (SUCCEEDED(hRes)) { LPTSTR pszURLData = (LPTSTR)GlobalLock(stgmedium.hGlobal); if (pszURLData) { if (iDropType == CITBDTYPE_URL) { STGMEDIUM stgmediumFGD;
// defaults
StrCpyN(pszUrl, pszURLData, INTERNET_MAX_URL_LENGTH); StrCpyN(pszName, pszURLData, MAX_NAME_QUICKLINK);
formatetc.cfFormat = (CLIPFORMAT) RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR); if (SUCCEEDED(pdtobj->GetData(&formatetc, &stgmediumFGD))) { FILEGROUPDESCRIPTOR *pfgd = (FILEGROUPDESCRIPTOR *)GlobalLock(stgmediumFGD.hGlobal); if (pfgd) { TCHAR szPath[MAX_PATH]; StrCpyN(szPath, pfgd->fgd[0].cFileName, ARRAYSIZE(szPath)); PathRemoveExtension(szPath); StrCpyN(pszName, szPath, MAX_NAME_QUICKLINK); GlobalUnlock(stgmediumFGD.hGlobal); } ReleaseStgMedium(&stgmediumFGD); } } else if (iDropType == CITBDTYPE_TEXT) { if (PathIsURL(pszURLData)) { StrCpyN(pszUrl, pszURLData, INTERNET_MAX_URL_LENGTH); StrCpyN(pszName, pszURLData, MAX_NAME_QUICKLINK); } else hRes = E_FAIL; } GlobalUnlock(stgmedium.hGlobal); } ReleaseStgMedium(&stgmedium); }
if (SUCCEEDED(hRes)) { if (!IsHTTPPrefixed(pszUrl) || SHRestricted2(REST_NoAddingSubscriptions, pszUrl, 0)) { hRes = E_FAIL; } } return hRes; }
HRESULT ScheduleDefault(LPCTSTR url, LPCTSTR name) { if (!IsHTTPPrefixed(url)) return E_INVALIDARG;
ISubscriptionMgr * pSub= NULL; HRESULT hr = CoInitialize(NULL); RETURN_ON_FAILURE(hr);
hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr, (void **)&pSub); CoUninitialize(); RETURN_ON_FAILURE(hr); ASSERT(pSub);
BSTR bstrURL = NULL, bstrName = NULL; hr = CreateBSTRFromTSTR(&bstrURL, url); if (S_OK == hr) hr = CreateBSTRFromTSTR(&bstrName, name);
// We need a perfectly valid structure.
SUBSCRIPTIONINFO subInfo; ZeroMemory((void *)&subInfo, sizeof (SUBSCRIPTIONINFO)); subInfo.cbSize = sizeof(SUBSCRIPTIONINFO);
if (S_OK == hr) hr = pSub->CreateSubscription(NULL, bstrURL, bstrName, CREATESUBS_NOUI, SUBSTYPE_URL, &subInfo);
SAFERELEASE(pSub); SAFEFREEBSTR(bstrURL); SAFEFREEBSTR(bstrName);
if (FAILED(hr)) { TraceMsg(TF_ALWAYS, "Failed to add default object."); TraceMsg(TF_ALWAYS, " hr = 0x%x\n", hr); return (FAILED(hr))?hr:E_FAIL; } else if (hr == S_FALSE) { TraceMsg(TF_SUBSFOLDER, "%s(%s) is already there.", url, name); return hr; }
return S_OK; }
|