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