windows-nt/Source/XPSP1/NT/shell/ext/webcheck/droptrgt.cpp
2020-09-26 16:20:57 +08:00

553 lines
14 KiB
C++

#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;
}