480 lines
13 KiB
C++
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;
|
||
|
}
|