Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

479 lines
13 KiB

  1. //
  2. // ITBDROP.CPP
  3. // routines for implementing OLE drop target capability
  4. // within the internet toolbar control
  5. //
  6. // History:
  7. // 07/13/96 t-mkim Created
  8. // 10/13/96 chrisg massive cleanup
  9. //
  10. #include "priv.h"
  11. #include "itbdrop.h"
  12. #include "sccls.h"
  13. #include "resource.h"
  14. #include "mluisupp.h"
  15. #ifdef UNIX
  16. #ifdef SIZEOF
  17. #undef SIZEOF
  18. #endif
  19. #define SIZEOF(x) sizeof(x) // has been checked for UNICODE correctness
  20. #endif
  21. #define MAX_NAME_QUICKLINK 40
  22. // Data type of the incoming data object.
  23. #define CITBDTYPE_NONE 0
  24. #define CITBDTYPE_HDROP 1
  25. #define CITBDTYPE_URL 2
  26. #define CITBDTYPE_TEXT 3
  27. // get an IDropTarget for shell special folders
  28. //
  29. HRESULT _GetSpecialDropTarget(UINT csidl, IDropTarget **ppdtgt)
  30. {
  31. IShellFolder *psfDesktop;
  32. *ppdtgt = NULL;
  33. HRESULT hres = SHGetDesktopFolder(&psfDesktop);
  34. if (SUCCEEDED(hres))
  35. {
  36. LPITEMIDLIST pidl;
  37. hres = SHGetSpecialFolderLocation(NULL, csidl, &pidl);
  38. if (SUCCEEDED(hres))
  39. {
  40. IShellFolder *psf;
  41. hres = psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (void **)&psf);
  42. if (SUCCEEDED(hres))
  43. {
  44. hres = psf->CreateViewObject(NULL, IID_IDropTarget, (void **)ppdtgt);
  45. psf->Release();
  46. }
  47. ILFree(pidl);
  48. }
  49. psfDesktop->Release();
  50. }
  51. return hres;
  52. }
  53. // Takes a variety of inputs and returns a string for drop targets.
  54. // szUrl: the URL
  55. // szName: the name (for quicklinks and the confo dialog boxes)
  56. // returns: NOERROR if succeeded
  57. //
  58. HRESULT _GetURLData(IDataObject *pdtobj, int iDropType, TCHAR *pszUrl, DWORD cchUrl, TCHAR *pszName)
  59. {
  60. HRESULT hRes = NOERROR;
  61. STGMEDIUM stgmedium;
  62. UINT cfFormat;
  63. *pszName = 0;
  64. *pszUrl = 0;
  65. switch (iDropType)
  66. {
  67. case CITBDTYPE_HDROP:
  68. cfFormat = CF_HDROP;
  69. break;
  70. case CITBDTYPE_URL:
  71. InitClipboardFormats();
  72. cfFormat = g_cfURL;
  73. break;
  74. case CITBDTYPE_TEXT:
  75. cfFormat = CF_TEXT;
  76. break;
  77. default:
  78. return E_UNEXPECTED;
  79. }
  80. // Get the parse string
  81. LPCSTR pszURL = (LPCSTR)DataObj_GetDataOfType(pdtobj, cfFormat, &stgmedium);
  82. if (pszURL)
  83. {
  84. if (iDropType == CITBDTYPE_HDROP)
  85. {
  86. ASSERT(stgmedium.tymed == TYMED_HGLOBAL);
  87. TCHAR szPath[MAX_PATH];
  88. DragQueryFile((HDROP)stgmedium.hGlobal, 0, szPath, ARRAYSIZE(szPath));
  89. // defaults...
  90. lstrcpyn(pszUrl, szPath, MAX_URL_STRING);
  91. lstrcpyn(pszName, szPath, MAX_NAME_QUICKLINK);
  92. SHFILEINFO sfi;
  93. DWORD_PTR bGotInfo = SHGetFileInfo(szPath, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME | SHGFI_ATTRIBUTES);
  94. if (bGotInfo)
  95. lstrcpyn(pszName, sfi.szDisplayName, MAX_NAME_QUICKLINK);
  96. if (bGotInfo && (sfi.dwAttributes & SFGAO_LINK))
  97. {
  98. LPITEMIDLIST pidl;
  99. if (SUCCEEDED(GetLinkTargetIDList(szPath, pszUrl, cchUrl, &pidl)))
  100. {
  101. // we only care about the name... thanks anyway.
  102. ILFree(pidl);
  103. }
  104. }
  105. }
  106. else
  107. {
  108. #ifdef UNICODE
  109. WCHAR wszURL[MAX_URL_STRING];
  110. SHAnsiToUnicode(pszURL, wszURL, ARRAYSIZE(wszURL));
  111. LPTSTR pszURLData = wszURL;
  112. #else
  113. LPTSTR pszURLData = pszURL;
  114. #endif
  115. if (iDropType == CITBDTYPE_URL)
  116. {
  117. // defaults
  118. lstrcpyn(pszUrl, pszURLData, MAX_URL_STRING);
  119. lstrcpyn(pszName, pszURLData, MAX_NAME_QUICKLINK);
  120. WCHAR szPath[MAX_PATH];
  121. if (SUCCEEDED(DataObj_GetNameFromFileDescriptor(pdtobj, szPath, ARRAYSIZE(szPath))))
  122. PathToDisplayNameW(szPath, pszName, MAX_NAME_QUICKLINK);
  123. }
  124. else // if (iDropType == CITBDTYPE_TEXT)
  125. {
  126. ASSERT(iDropType == CITBDTYPE_TEXT);
  127. lstrcpyn(pszUrl, pszURLData, MAX_URL_STRING);
  128. lstrcpyn(pszName, pszURLData, MAX_NAME_QUICKLINK);
  129. }
  130. }
  131. ReleaseStgMediumHGLOBAL(NULL, &stgmedium);
  132. }
  133. else
  134. {
  135. hRes = E_FAIL;
  136. }
  137. return hRes;
  138. }
  139. // Displays a dialog asking for confirmation of drop-set operations.
  140. // Returns: User's response to the dialog box: YES = TRUE, NO = FALSE
  141. //
  142. BOOL _ConfirmChangeQuickLink(HWND hwndParent, TCHAR *pszName, int iTarget)
  143. {
  144. MSGBOXPARAMS mbp;
  145. TCHAR szHeader[64];
  146. TCHAR szBuffer [MAX_NAME_QUICKLINK + 64];
  147. TCHAR szCaption [MAX_NAME_QUICKLINK + 64];
  148. UINT titleID, textID, iconID;
  149. switch (iTarget)
  150. {
  151. case TBIDM_HOME:
  152. titleID = IDS_SETHOME_TITLE;
  153. textID = IDS_SETHOME_TEXT;
  154. iconID = IDI_HOMEPAGE;
  155. break;
  156. #if 0
  157. case TBIDM_SEARCH:
  158. titleID = IDS_SETSEARCH_TITLE;
  159. textID = IDS_SETSEARCH_TEXT;
  160. iconID = IDI_FRAME; // Warning if you unif0 this: IDI_FRAME is not in this dll
  161. break;
  162. #endif
  163. default:
  164. return FALSE; // We should never get here!
  165. }
  166. mbp.cbSize = sizeof (MSGBOXPARAMS);
  167. mbp.hwndOwner = hwndParent;
  168. mbp.hInstance = HinstShdocvw();
  169. mbp.dwStyle = MB_YESNO | MB_USERICON;
  170. MLLoadString(titleID, szCaption, ARRAYSIZE (szCaption));
  171. mbp.lpszCaption = szCaption;
  172. mbp.lpszIcon = MAKEINTRESOURCE (iconID);
  173. mbp.dwContextHelpId = 0;
  174. mbp.lpfnMsgBoxCallback = NULL;
  175. mbp.dwLanguageId = LANGIDFROMLCID (g_lcidLocale);
  176. MLLoadString(textID, szHeader, ARRAYSIZE (szHeader));
  177. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), szHeader, pszName);
  178. mbp.lpszText = szBuffer;
  179. return MessageBoxIndirect(&mbp) == IDYES;
  180. }
  181. // Creates an instance of CITBarDropTarget. ptr is a pointer to the parent
  182. // CInternetToolbar.
  183. //
  184. CITBarDropTarget::CITBarDropTarget(HWND hwnd, int iTarget) :
  185. _cRef(1), _iDropType(CITBDTYPE_NONE), _hwndParent(hwnd), _iTarget(iTarget)
  186. {
  187. }
  188. STDMETHODIMP CITBarDropTarget::QueryInterface(REFIID iid, void **ppvObj)
  189. {
  190. if (IsEqualIID (iid, IID_IUnknown) || IsEqualIID (iid, IID_IDropTarget))
  191. {
  192. *ppvObj = SAFECAST(this, IDropTarget*);
  193. AddRef();
  194. return NOERROR;
  195. }
  196. *ppvObj = NULL;
  197. return E_NOINTERFACE;
  198. }
  199. STDMETHODIMP_(ULONG) CITBarDropTarget::AddRef()
  200. {
  201. _cRef++;
  202. return _cRef;
  203. }
  204. STDMETHODIMP_(ULONG) CITBarDropTarget::Release()
  205. {
  206. _cRef--;
  207. if (_cRef > 0)
  208. return _cRef;
  209. delete this;
  210. return 0;
  211. }
  212. typedef struct
  213. {
  214. int iTarget;
  215. int iDropType;
  216. HWND hwnd;
  217. TCHAR szUrl [MAX_URL_STRING];
  218. TCHAR szName [MAX_NAME_QUICKLINK];
  219. } DROPDATA;
  220. DWORD CALLBACK ITBarDropThreadProc(void *pv)
  221. {
  222. DROPDATA *pdd = (DROPDATA *)pv;
  223. switch (pdd->iTarget)
  224. {
  225. case TBIDM_HOME:
  226. if (pdd->iDropType != CITBDTYPE_TEXT)
  227. {
  228. if (_ConfirmChangeQuickLink(pdd->hwnd, pdd->szName, pdd->iTarget)) {
  229. ASSERT(pdd->iTarget == TBIDM_HOME);
  230. // currently don't support pdd->itarget == TBIDM_SEARCH
  231. //(pdd->iTarget == TBIDM_HOME) ? DVIDM_GOHOME : DVIDM_GOSEARCH);
  232. _SetStdLocation(pdd->szUrl, DVIDM_GOHOME);
  233. }
  234. }
  235. break;
  236. case TBIDM_SEARCH:
  237. ASSERT(0);
  238. break;
  239. }
  240. LocalFree(pdd);
  241. return 0;
  242. }
  243. STDMETHODIMP CITBarDropTarget::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  244. {
  245. ASSERT(pdtobj);
  246. _DragEnter(_hwndParent, ptl, pdtobj);
  247. if (_iTarget == TBIDM_FAVORITES)
  248. {
  249. if (SUCCEEDED(_GetSpecialDropTarget(CSIDL_FAVORITES, &_pdrop)))
  250. _pdrop->DragEnter(pdtobj, grfKeyState, ptl, pdwEffect);
  251. else
  252. *pdwEffect = DROPEFFECT_NONE;
  253. return NOERROR;
  254. }
  255. else if (_iTarget == TBIDM_HOME)
  256. {
  257. HKEY hkeyRest = 0;
  258. DWORD dwValue = 0;
  259. DWORD dwLen = sizeof(DWORD);
  260. // Check if setting home page is restricted
  261. if (RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_SET_HOMEPAGE_RESTRICTION, 0,
  262. KEY_READ, &hkeyRest) == ERROR_SUCCESS)
  263. {
  264. if (RegQueryValueEx(hkeyRest, REGVAL_HOMEPAGE_RESTRICTION, NULL, NULL,
  265. (LPBYTE)&dwValue, &dwLen) == ERROR_SUCCESS
  266. && dwValue)
  267. {
  268. return E_ACCESSDENIED;
  269. }
  270. RegCloseKey(hkeyRest);
  271. }
  272. }
  273. InitClipboardFormats();
  274. // Find the drop object's data format.
  275. FORMATETC fe = {g_cfURL, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  276. if (NOERROR == pdtobj->QueryGetData (&fe))
  277. {
  278. _iDropType = CITBDTYPE_URL;
  279. }
  280. else if (fe.cfFormat = CF_HDROP, NOERROR == pdtobj->QueryGetData (&fe))
  281. {
  282. _iDropType = CITBDTYPE_HDROP;
  283. }
  284. else if (fe.cfFormat = CF_TEXT, NOERROR == pdtobj->QueryGetData (&fe))
  285. {
  286. _iDropType = CITBDTYPE_TEXT;
  287. // We want to eventually pick through the text for an
  288. // URL, but right now we just leave it unmolested.
  289. }
  290. DragOver (grfKeyState, ptl, pdwEffect);
  291. return NOERROR;
  292. }
  293. STDMETHODIMP CITBarDropTarget::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  294. {
  295. DWORD dwEffectAvail;
  296. _DragMove(_hwndParent, ptl);
  297. if (_iTarget == TBIDM_FAVORITES)
  298. {
  299. if (_pdrop)
  300. return _pdrop->DragOver(grfKeyState, ptl, pdwEffect);
  301. *pdwEffect = DROPEFFECT_NONE;
  302. return NOERROR;
  303. }
  304. ASSERT(!_pdrop);
  305. if (_iDropType == CITBDTYPE_NONE)
  306. {
  307. *pdwEffect = DROPEFFECT_NONE;
  308. return NOERROR;
  309. }
  310. dwEffectAvail = DROPEFFECT_NONE;
  311. switch (_iTarget)
  312. {
  313. case TBIDM_HOME:
  314. case TBIDM_SEARCH:
  315. if (_iDropType == CITBDTYPE_TEXT)
  316. {
  317. // CF_TEXT doesn't do link.
  318. }
  319. else
  320. dwEffectAvail = DROPEFFECT_LINK;
  321. break;
  322. }
  323. *pdwEffect &= dwEffectAvail;
  324. return NOERROR;
  325. }
  326. STDMETHODIMP CITBarDropTarget::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  327. {
  328. BOOL fSafe = TRUE;
  329. LPITEMIDLIST pidl;
  330. if (_pdrop)
  331. {
  332. ASSERT(_iTarget == TBIDM_FAVORITES);
  333. //
  334. // Force a linking since we are passing straight through to the folder.
  335. // This avoids confusion when dragging to the toolbar button.
  336. //
  337. // FEATURE: this should really go through the "Add to Favorites" UI
  338. //
  339. // When forcing a link, make sure that you can move it. If you cannot move it,
  340. // then we rely on the prefered effect of the data object. Why? Well, the history
  341. // folder only allows a copy. If you just whack this to LINK, the shell folder hoses
  342. // the drag images (Does a DAD_SetDragImage(NULL), blowing away the information about
  343. // the last locked window, without unlocking it.). So, if you can move the item,
  344. // you can link to it (I guess), but if you cannot move it, do whatever.
  345. // - (lamadio) 1.3.99
  346. if (*pdwEffect & DROPEFFECT_MOVE)
  347. *pdwEffect = DROPEFFECT_LINK;
  348. if (TBIDM_FAVORITES == _iTarget &&
  349. SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0)))
  350. {
  351. fSafe = IEIsLinkSafe(_hwndParent, pidl, ILS_ADDTOFAV);
  352. ILFree(pidl);
  353. }
  354. if (fSafe)
  355. {
  356. _pdrop->Drop(pdtobj, grfKeyState, pt, pdwEffect);
  357. }
  358. else
  359. {
  360. pdtobj->Release(); // Match Release called in _pdrop->Drop.
  361. }
  362. DAD_DragLeave();
  363. _pdrop->Release();
  364. _pdrop = NULL;
  365. }
  366. else
  367. {
  368. if (TBIDM_HOME == _iTarget &&
  369. SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0)))
  370. {
  371. fSafe = IEIsLinkSafe(_hwndParent, pidl, ILS_HOME);
  372. ILFree(pidl);
  373. }
  374. if (fSafe)
  375. {
  376. DROPDATA *pdd = (DROPDATA *)LocalAlloc (LPTR, sizeof(DROPDATA));
  377. if (pdd)
  378. {
  379. pdd->iTarget = _iTarget;
  380. pdd->iDropType = _iDropType;
  381. pdd->hwnd = _hwndParent;
  382. // do this async so we don't block the source of the drag durring our UI
  383. if (FAILED(_GetURLData(pdtobj, _iDropType, pdd->szUrl, ARRAYSIZE(pdd->szUrl), pdd->szName)) ||
  384. !SHCreateThread(ITBarDropThreadProc, pdd, 0, NULL))
  385. LocalFree(pdd);
  386. }
  387. }
  388. DragLeave();
  389. }
  390. return NOERROR;
  391. }
  392. STDMETHODIMP CITBarDropTarget::DragLeave(void)
  393. {
  394. DAD_DragLeave();
  395. // Check if we should to pass to the favorites dt.
  396. if (_pdrop)
  397. {
  398. ASSERT(_iTarget == TBIDM_FAVORITES);
  399. _pdrop->DragLeave();
  400. _pdrop->Release();
  401. _pdrop = NULL;
  402. }
  403. _iDropType = CITBDTYPE_NONE;
  404. return NOERROR;
  405. }