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

480 lines
13 KiB
C++

//
// ITBDROP.CPP
// routines for implementing OLE drop target capability
// within the internet toolbar control
//
// History:
// 07/13/96 t-mkim Created
// 10/13/96 chrisg massive cleanup
//
#include "priv.h"
#include "itbdrop.h"
#include "sccls.h"
#include "resource.h"
#include "mluisupp.h"
#ifdef UNIX
#ifdef SIZEOF
#undef SIZEOF
#endif
#define SIZEOF(x) sizeof(x) // has been checked for UNICODE correctness
#endif
#define MAX_NAME_QUICKLINK 40
// Data type of the incoming data object.
#define CITBDTYPE_NONE 0
#define CITBDTYPE_HDROP 1
#define CITBDTYPE_URL 2
#define CITBDTYPE_TEXT 3
// get an IDropTarget for shell special folders
//
HRESULT _GetSpecialDropTarget(UINT csidl, IDropTarget **ppdtgt)
{
IShellFolder *psfDesktop;
*ppdtgt = NULL;
HRESULT hres = SHGetDesktopFolder(&psfDesktop);
if (SUCCEEDED(hres))
{
LPITEMIDLIST pidl;
hres = SHGetSpecialFolderLocation(NULL, csidl, &pidl);
if (SUCCEEDED(hres))
{
IShellFolder *psf;
hres = psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (void **)&psf);
if (SUCCEEDED(hres))
{
hres = psf->CreateViewObject(NULL, IID_IDropTarget, (void **)ppdtgt);
psf->Release();
}
ILFree(pidl);
}
psfDesktop->Release();
}
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, DWORD cchUrl, TCHAR *pszName)
{
HRESULT hRes = NOERROR;
STGMEDIUM stgmedium;
UINT cfFormat;
*pszName = 0;
*pszUrl = 0;
switch (iDropType)
{
case CITBDTYPE_HDROP:
cfFormat = CF_HDROP;
break;
case CITBDTYPE_URL:
InitClipboardFormats();
cfFormat = g_cfURL;
break;
case CITBDTYPE_TEXT:
cfFormat = CF_TEXT;
break;
default:
return E_UNEXPECTED;
}
// Get the parse string
LPCSTR pszURL = (LPCSTR)DataObj_GetDataOfType(pdtobj, cfFormat, &stgmedium);
if (pszURL)
{
if (iDropType == CITBDTYPE_HDROP)
{
ASSERT(stgmedium.tymed == TYMED_HGLOBAL);
TCHAR szPath[MAX_PATH];
DragQueryFile((HDROP)stgmedium.hGlobal, 0, szPath, ARRAYSIZE(szPath));
// defaults...
lstrcpyn(pszUrl, szPath, MAX_URL_STRING);
lstrcpyn(pszName, szPath, MAX_NAME_QUICKLINK);
SHFILEINFO sfi;
DWORD_PTR bGotInfo = SHGetFileInfo(szPath, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME | SHGFI_ATTRIBUTES);
if (bGotInfo)
lstrcpyn(pszName, sfi.szDisplayName, MAX_NAME_QUICKLINK);
if (bGotInfo && (sfi.dwAttributes & SFGAO_LINK))
{
LPITEMIDLIST pidl;
if (SUCCEEDED(GetLinkTargetIDList(szPath, pszUrl, cchUrl, &pidl)))
{
// we only care about the name... thanks anyway.
ILFree(pidl);
}
}
}
else
{
#ifdef UNICODE
WCHAR wszURL[MAX_URL_STRING];
SHAnsiToUnicode(pszURL, wszURL, ARRAYSIZE(wszURL));
LPTSTR pszURLData = wszURL;
#else
LPTSTR pszURLData = pszURL;
#endif
if (iDropType == CITBDTYPE_URL)
{
// defaults
lstrcpyn(pszUrl, pszURLData, MAX_URL_STRING);
lstrcpyn(pszName, pszURLData, MAX_NAME_QUICKLINK);
WCHAR szPath[MAX_PATH];
if (SUCCEEDED(DataObj_GetNameFromFileDescriptor(pdtobj, szPath, ARRAYSIZE(szPath))))
PathToDisplayNameW(szPath, pszName, MAX_NAME_QUICKLINK);
}
else // if (iDropType == CITBDTYPE_TEXT)
{
ASSERT(iDropType == CITBDTYPE_TEXT);
lstrcpyn(pszUrl, pszURLData, MAX_URL_STRING);
lstrcpyn(pszName, pszURLData, MAX_NAME_QUICKLINK);
}
}
ReleaseStgMediumHGLOBAL(NULL, &stgmedium);
}
else
{
hRes = E_FAIL;
}
return hRes;
}
// Displays a dialog asking for confirmation of drop-set operations.
// Returns: User's response to the dialog box: YES = TRUE, NO = FALSE
//
BOOL _ConfirmChangeQuickLink(HWND hwndParent, TCHAR *pszName, int iTarget)
{
MSGBOXPARAMS mbp;
TCHAR szHeader[64];
TCHAR szBuffer [MAX_NAME_QUICKLINK + 64];
TCHAR szCaption [MAX_NAME_QUICKLINK + 64];
UINT titleID, textID, iconID;
switch (iTarget)
{
case TBIDM_HOME:
titleID = IDS_SETHOME_TITLE;
textID = IDS_SETHOME_TEXT;
iconID = IDI_HOMEPAGE;
break;
#if 0
case TBIDM_SEARCH:
titleID = IDS_SETSEARCH_TITLE;
textID = IDS_SETSEARCH_TEXT;
iconID = IDI_FRAME; // Warning if you unif0 this: IDI_FRAME is not in this dll
break;
#endif
default:
return FALSE; // We should never get here!
}
mbp.cbSize = sizeof (MSGBOXPARAMS);
mbp.hwndOwner = hwndParent;
mbp.hInstance = HinstShdocvw();
mbp.dwStyle = MB_YESNO | MB_USERICON;
MLLoadString(titleID, szCaption, ARRAYSIZE (szCaption));
mbp.lpszCaption = szCaption;
mbp.lpszIcon = MAKEINTRESOURCE (iconID);
mbp.dwContextHelpId = 0;
mbp.lpfnMsgBoxCallback = NULL;
mbp.dwLanguageId = LANGIDFROMLCID (g_lcidLocale);
MLLoadString(textID, szHeader, ARRAYSIZE (szHeader));
wnsprintf(szBuffer, ARRAYSIZE(szBuffer), szHeader, pszName);
mbp.lpszText = szBuffer;
return MessageBoxIndirect(&mbp) == IDYES;
}
// Creates an instance of CITBarDropTarget. ptr is a pointer to the parent
// CInternetToolbar.
//
CITBarDropTarget::CITBarDropTarget(HWND hwnd, int iTarget) :
_cRef(1), _iDropType(CITBDTYPE_NONE), _hwndParent(hwnd), _iTarget(iTarget)
{
}
STDMETHODIMP CITBarDropTarget::QueryInterface(REFIID iid, void **ppvObj)
{
if (IsEqualIID (iid, IID_IUnknown) || IsEqualIID (iid, IID_IDropTarget))
{
*ppvObj = SAFECAST(this, IDropTarget*);
AddRef();
return NOERROR;
}
*ppvObj = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CITBarDropTarget::AddRef()
{
_cRef++;
return _cRef;
}
STDMETHODIMP_(ULONG) CITBarDropTarget::Release()
{
_cRef--;
if (_cRef > 0)
return _cRef;
delete this;
return 0;
}
typedef struct
{
int iTarget;
int iDropType;
HWND hwnd;
TCHAR szUrl [MAX_URL_STRING];
TCHAR szName [MAX_NAME_QUICKLINK];
} DROPDATA;
DWORD CALLBACK ITBarDropThreadProc(void *pv)
{
DROPDATA *pdd = (DROPDATA *)pv;
switch (pdd->iTarget)
{
case TBIDM_HOME:
if (pdd->iDropType != CITBDTYPE_TEXT)
{
if (_ConfirmChangeQuickLink(pdd->hwnd, pdd->szName, pdd->iTarget)) {
ASSERT(pdd->iTarget == TBIDM_HOME);
// currently don't support pdd->itarget == TBIDM_SEARCH
//(pdd->iTarget == TBIDM_HOME) ? DVIDM_GOHOME : DVIDM_GOSEARCH);
_SetStdLocation(pdd->szUrl, DVIDM_GOHOME);
}
}
break;
case TBIDM_SEARCH:
ASSERT(0);
break;
}
LocalFree(pdd);
return 0;
}
STDMETHODIMP CITBarDropTarget::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
ASSERT(pdtobj);
_DragEnter(_hwndParent, ptl, pdtobj);
if (_iTarget == TBIDM_FAVORITES)
{
if (SUCCEEDED(_GetSpecialDropTarget(CSIDL_FAVORITES, &_pdrop)))
_pdrop->DragEnter(pdtobj, grfKeyState, ptl, pdwEffect);
else
*pdwEffect = DROPEFFECT_NONE;
return NOERROR;
}
else if (_iTarget == TBIDM_HOME)
{
HKEY hkeyRest = 0;
DWORD dwValue = 0;
DWORD dwLen = sizeof(DWORD);
// Check if setting home page is restricted
if (RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_SET_HOMEPAGE_RESTRICTION, 0,
KEY_READ, &hkeyRest) == ERROR_SUCCESS)
{
if (RegQueryValueEx(hkeyRest, REGVAL_HOMEPAGE_RESTRICTION, NULL, NULL,
(LPBYTE)&dwValue, &dwLen) == ERROR_SUCCESS
&& dwValue)
{
return E_ACCESSDENIED;
}
RegCloseKey(hkeyRest);
}
}
InitClipboardFormats();
// Find the drop object's data format.
FORMATETC fe = {g_cfURL, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
if (NOERROR == pdtobj->QueryGetData (&fe))
{
_iDropType = CITBDTYPE_URL;
}
else if (fe.cfFormat = CF_HDROP, NOERROR == pdtobj->QueryGetData (&fe))
{
_iDropType = CITBDTYPE_HDROP;
}
else if (fe.cfFormat = CF_TEXT, NOERROR == pdtobj->QueryGetData (&fe))
{
_iDropType = CITBDTYPE_TEXT;
// We want to eventually pick through the text for an
// URL, but right now we just leave it unmolested.
}
DragOver (grfKeyState, ptl, pdwEffect);
return NOERROR;
}
STDMETHODIMP CITBarDropTarget::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
DWORD dwEffectAvail;
_DragMove(_hwndParent, ptl);
if (_iTarget == TBIDM_FAVORITES)
{
if (_pdrop)
return _pdrop->DragOver(grfKeyState, ptl, pdwEffect);
*pdwEffect = DROPEFFECT_NONE;
return NOERROR;
}
ASSERT(!_pdrop);
if (_iDropType == CITBDTYPE_NONE)
{
*pdwEffect = DROPEFFECT_NONE;
return NOERROR;
}
dwEffectAvail = DROPEFFECT_NONE;
switch (_iTarget)
{
case TBIDM_HOME:
case TBIDM_SEARCH:
if (_iDropType == CITBDTYPE_TEXT)
{
// CF_TEXT doesn't do link.
}
else
dwEffectAvail = DROPEFFECT_LINK;
break;
}
*pdwEffect &= dwEffectAvail;
return NOERROR;
}
STDMETHODIMP CITBarDropTarget::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
BOOL fSafe = TRUE;
LPITEMIDLIST pidl;
if (_pdrop)
{
ASSERT(_iTarget == TBIDM_FAVORITES);
//
// Force a linking since we are passing straight through to the folder.
// This avoids confusion when dragging to the toolbar button.
//
// FEATURE: this should really go through the "Add to Favorites" UI
//
// When forcing a link, make sure that you can move it. If you cannot move it,
// then we rely on the prefered effect of the data object. Why? Well, the history
// folder only allows a copy. If you just whack this to LINK, the shell folder hoses
// the drag images (Does a DAD_SetDragImage(NULL), blowing away the information about
// the last locked window, without unlocking it.). So, if you can move the item,
// you can link to it (I guess), but if you cannot move it, do whatever.
// - (lamadio) 1.3.99
if (*pdwEffect & DROPEFFECT_MOVE)
*pdwEffect = DROPEFFECT_LINK;
if (TBIDM_FAVORITES == _iTarget &&
SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0)))
{
fSafe = IEIsLinkSafe(_hwndParent, pidl, ILS_ADDTOFAV);
ILFree(pidl);
}
if (fSafe)
{
_pdrop->Drop(pdtobj, grfKeyState, pt, pdwEffect);
}
else
{
pdtobj->Release(); // Match Release called in _pdrop->Drop.
}
DAD_DragLeave();
_pdrop->Release();
_pdrop = NULL;
}
else
{
if (TBIDM_HOME == _iTarget &&
SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0)))
{
fSafe = IEIsLinkSafe(_hwndParent, pidl, ILS_HOME);
ILFree(pidl);
}
if (fSafe)
{
DROPDATA *pdd = (DROPDATA *)LocalAlloc (LPTR, sizeof(DROPDATA));
if (pdd)
{
pdd->iTarget = _iTarget;
pdd->iDropType = _iDropType;
pdd->hwnd = _hwndParent;
// do this async so we don't block the source of the drag durring our UI
if (FAILED(_GetURLData(pdtobj, _iDropType, pdd->szUrl, ARRAYSIZE(pdd->szUrl), pdd->szName)) ||
!SHCreateThread(ITBarDropThreadProc, pdd, 0, NULL))
LocalFree(pdd);
}
}
DragLeave();
}
return NOERROR;
}
STDMETHODIMP CITBarDropTarget::DragLeave(void)
{
DAD_DragLeave();
// Check if we should to pass to the favorites dt.
if (_pdrop)
{
ASSERT(_iTarget == TBIDM_FAVORITES);
_pdrop->DragLeave();
_pdrop->Release();
_pdrop = NULL;
}
_iDropType = CITBDTYPE_NONE;
return NOERROR;
}