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.

552 lines
14 KiB

  1. #include "private.h"
  2. #include "offl_cpp.h"
  3. #include "subsmgrp.h"
  4. HRESULT _GetURLData(IDataObject *, int, TCHAR *, TCHAR *);
  5. HRESULT _ConvertHDROPData(IDataObject *, BOOL);
  6. HRESULT ScheduleDefault(LPCTSTR, LPCTSTR);
  7. #define CITBDTYPE_HDROP 1
  8. #define CITBDTYPE_URL 2
  9. #define CITBDTYPE_TEXT 3
  10. //
  11. // Constructor
  12. //
  13. COfflineDropTarget::COfflineDropTarget(HWND hwndParent)
  14. {
  15. m_cRefs = 1;
  16. m_hwndParent = hwndParent;
  17. m_pDataObj = NULL;
  18. m_grfKeyStateLast = 0;
  19. m_fHasHDROP = FALSE;
  20. m_fHasSHELLURL = FALSE;
  21. m_fHasTEXT = FALSE;
  22. m_dwEffectLastReturned = 0;
  23. DllAddRef();
  24. }
  25. //
  26. // Destructor
  27. //
  28. COfflineDropTarget::~COfflineDropTarget()
  29. {
  30. DllRelease();
  31. }
  32. //
  33. // QueryInterface
  34. //
  35. STDMETHODIMP COfflineDropTarget::QueryInterface(REFIID riid, LPVOID *ppv)
  36. {
  37. HRESULT hr = E_NOINTERFACE;
  38. *ppv = NULL;
  39. // Any interface on this object is the object pointer
  40. if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDropTarget))
  41. {
  42. *ppv = (LPDROPTARGET)this;
  43. AddRef();
  44. hr = NOERROR;
  45. }
  46. return hr;
  47. }
  48. //
  49. // AddRef
  50. //
  51. STDMETHODIMP_(ULONG) COfflineDropTarget::AddRef()
  52. {
  53. return ++m_cRefs;
  54. }
  55. //
  56. // Release
  57. //
  58. STDMETHODIMP_(ULONG) COfflineDropTarget::Release()
  59. {
  60. if (0L != --m_cRefs)
  61. {
  62. return m_cRefs;
  63. }
  64. delete this;
  65. return 0L;
  66. }
  67. //
  68. // DragEnter
  69. //
  70. STDMETHODIMP COfflineDropTarget::DragEnter(LPDATAOBJECT pDataObj,
  71. DWORD grfKeyState,
  72. POINTL pt,
  73. LPDWORD pdwEffect)
  74. {
  75. // Release any old data object we might have
  76. // TraceMsg(TF_SUBSFOLDER, TEXT("odt - DragEnter"));
  77. if (m_pDataObj)
  78. {
  79. m_pDataObj->Release();
  80. }
  81. m_grfKeyStateLast = grfKeyState;
  82. m_pDataObj = pDataObj;
  83. //
  84. // See if we will be able to get CF_HDROP from this guy
  85. //
  86. if (pDataObj)
  87. {
  88. pDataObj->AddRef();
  89. TCHAR url[INTERNET_MAX_URL_LENGTH], name[MAX_NAME_QUICKLINK];
  90. FORMATETC fe = {(CLIPFORMAT) RegisterClipboardFormat(CFSTR_SHELLURL),
  91. NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  92. m_fHasSHELLURL = m_fHasHDROP = m_fHasTEXT = FALSE;
  93. if (NOERROR == pDataObj->QueryGetData(&fe))
  94. {
  95. TraceMsg(TF_SUBSFOLDER, "odt - DragEnter : SHELLURL!");
  96. m_fHasSHELLURL =
  97. (NOERROR == _GetURLData(pDataObj,CITBDTYPE_URL,url,name));
  98. }
  99. if (fe.cfFormat = CF_HDROP, NOERROR == pDataObj->QueryGetData(&fe))
  100. {
  101. TraceMsg(TF_SUBSFOLDER, "odt - DragEnter : HDROP!");
  102. m_fHasHDROP = (NOERROR ==
  103. _ConvertHDROPData(pDataObj, FALSE));
  104. }
  105. if (fe.cfFormat = CF_TEXT, NOERROR == pDataObj->QueryGetData(&fe))
  106. {
  107. TraceMsg(TF_SUBSFOLDER, "odt - DragEnter : TEXT!");
  108. m_fHasTEXT =
  109. (NOERROR == _GetURLData(pDataObj,CITBDTYPE_TEXT,url,name));
  110. }
  111. }
  112. // Save the drop effect
  113. if (pdwEffect)
  114. {
  115. *pdwEffect = m_dwEffectLastReturned = GetDropEffect(pdwEffect);
  116. }
  117. return S_OK;
  118. }
  119. //
  120. // GetDropEffect
  121. //
  122. DWORD COfflineDropTarget::GetDropEffect(LPDWORD pdwEffect)
  123. {
  124. ASSERT(pdwEffect);
  125. if (m_fHasSHELLURL || m_fHasTEXT)
  126. {
  127. return *pdwEffect & (DROPEFFECT_COPY | DROPEFFECT_LINK);
  128. }
  129. else if (m_fHasHDROP) {
  130. return *pdwEffect & (DROPEFFECT_COPY );
  131. }
  132. else
  133. {
  134. return DROPEFFECT_NONE;
  135. }
  136. }
  137. //
  138. // DragOver
  139. //
  140. STDMETHODIMP COfflineDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
  141. {
  142. // TraceMsg(TF_SUBSFOLDER, TEXT("odt - DragOver"));
  143. if (m_grfKeyStateLast == grfKeyState)
  144. {
  145. // Return the effect we saved at dragenter time
  146. if (*pdwEffect)
  147. {
  148. *pdwEffect = m_dwEffectLastReturned;
  149. }
  150. }
  151. else
  152. {
  153. if (*pdwEffect)
  154. {
  155. *pdwEffect = m_dwEffectLastReturned = GetDropEffect(pdwEffect);
  156. }
  157. }
  158. m_grfKeyStateLast = grfKeyState;
  159. return S_OK;
  160. }
  161. //
  162. // DragLeave
  163. //
  164. STDMETHODIMP COfflineDropTarget::DragLeave()
  165. {
  166. // TraceMsg(TF_SUBSFOLDER, TEXT("odt - DragLeave"));
  167. if (m_pDataObj)
  168. {
  169. m_pDataObj->Release();
  170. m_pDataObj = NULL;
  171. }
  172. return S_OK;
  173. }
  174. //
  175. // Drop
  176. //
  177. STDMETHODIMP COfflineDropTarget::Drop(LPDATAOBJECT pDataObj,
  178. DWORD grfKeyState,
  179. POINTL pt,
  180. LPDWORD pdwEffect)
  181. {
  182. // UINT idCmd; // Choice from drop popup menu
  183. HRESULT hr = S_OK;
  184. //
  185. // Take the new data object, since OLE can give us a different one than
  186. // it did in DragEnter
  187. //
  188. // TraceMsg(TF_SUBSFOLDER, TEXT("odt - Drop"));
  189. if (m_pDataObj)
  190. {
  191. m_pDataObj->Release();
  192. }
  193. m_pDataObj = pDataObj;
  194. if (pDataObj)
  195. {
  196. pDataObj->AddRef();
  197. }
  198. // If the dataobject doesn't have an HDROP, its not much good to us
  199. *pdwEffect &= DROPEFFECT_COPY|DROPEFFECT_LINK;
  200. if (!(*pdwEffect)) {
  201. DragLeave();
  202. return S_OK;
  203. }
  204. hr = E_NOINTERFACE;
  205. if (m_fHasHDROP)
  206. hr = _ConvertHDROPData(pDataObj, TRUE);
  207. else {
  208. TCHAR url[INTERNET_MAX_URL_LENGTH], name[MAX_NAME_QUICKLINK];
  209. if (m_fHasSHELLURL)
  210. hr = _GetURLData(pDataObj, CITBDTYPE_URL, url, name);
  211. if (FAILED(hr) && m_fHasTEXT)
  212. hr = _GetURLData(pDataObj, CITBDTYPE_TEXT, url, name);
  213. if (SUCCEEDED(hr)) {
  214. TraceMsg(TF_SUBSFOLDER, "URL: %s, Name: %s", url, name);
  215. hr = ScheduleDefault(url, name);
  216. }
  217. }
  218. if (FAILED(hr))
  219. {
  220. TraceMsg(TF_SUBSFOLDER, "Couldn't DROP");
  221. }
  222. DragLeave();
  223. return hr;
  224. }
  225. HRESULT _CLSIDFromExtension(
  226. LPCTSTR pszExt,
  227. CLSID *pclsid)
  228. {
  229. TCHAR szProgID[80];
  230. long cb = SIZEOF(szProgID);
  231. if (RegQueryValue(HKEY_CLASSES_ROOT, pszExt, szProgID, &cb) == ERROR_SUCCESS)
  232. {
  233. TCHAR szCLSID[80];
  234. StrCatN(szProgID, TEXT("\\CLSID"), ARRAYSIZE(szProgID));
  235. cb = SIZEOF(szCLSID);
  236. if (RegQueryValue(HKEY_CLASSES_ROOT, szProgID, szCLSID, &cb) == ERROR_SUCCESS)
  237. {
  238. // FEATURE (scotth): call shell32's SHCLSIDFromString once it
  239. // exports A/W versions. This would clean this
  240. // up.
  241. #ifdef UNICODE
  242. return CLSIDFromString(szCLSID, pclsid);
  243. #else
  244. WCHAR wszCLSID[80];
  245. MultiByteToWideChar(CP_ACP, 0, szCLSID, -1, wszCLSID, ARRAYSIZE(wszCLSID));
  246. return CLSIDFromString(wszCLSID, pclsid);
  247. #endif
  248. }
  249. }
  250. return E_FAIL;
  251. }
  252. // get the target of a shortcut. this uses IShellLink which
  253. // Internet Shortcuts (.URL) and Shell Shortcuts (.LNK) support so
  254. // it should work generally
  255. //
  256. HRESULT _GetURLTarget(LPCTSTR pszPath, LPTSTR pszTarget, UINT cch)
  257. {
  258. IShellLink *psl;
  259. HRESULT hr = E_FAIL;
  260. CLSID clsid;
  261. if (FAILED(_CLSIDFromExtension(PathFindExtension(pszPath), &clsid)))
  262. clsid = CLSID_ShellLink; // assume it's a shell link
  263. hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&psl);
  264. if (SUCCEEDED(hr))
  265. {
  266. IPersistFile *ppf;
  267. hr = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
  268. if (SUCCEEDED(hr))
  269. {
  270. #ifdef UNICODE
  271. hr = ppf->Load(pszPath, 0);
  272. #else
  273. WCHAR wszPath[MAX_PATH];
  274. MultiByteToWideChar(CP_ACP, 0, pszPath, -1, wszPath, ARRAYSIZE(wszPath));
  275. hr = ppf->Load (wszPath, 0);
  276. #endif
  277. ppf->Release();
  278. }
  279. if (SUCCEEDED(hr)) {
  280. IUniformResourceLocator * purl;
  281. hr = psl->QueryInterface(IID_IUniformResourceLocator,(void**)&purl);
  282. if (SUCCEEDED(hr))
  283. purl->Release();
  284. }
  285. if (SUCCEEDED(hr))
  286. hr = psl->GetPath(pszTarget, cch, NULL, SLGP_UNCPRIORITY);
  287. psl->Release();
  288. }
  289. return hr;
  290. }
  291. HRESULT _ConvertHDROPData(IDataObject *pdtobj, BOOL bSubscribe)
  292. {
  293. HRESULT hRes = NOERROR;
  294. STGMEDIUM stgmedium;
  295. FORMATETC formatetc;
  296. TCHAR url[INTERNET_MAX_URL_LENGTH];
  297. TCHAR name[MAX_NAME_QUICKLINK];
  298. name[0] = 0;
  299. url[0] = 0;
  300. formatetc.cfFormat = CF_HDROP;
  301. formatetc.ptd = NULL;
  302. formatetc.dwAspect = DVASPECT_CONTENT;
  303. formatetc.lindex = -1;
  304. formatetc.tymed = TYMED_HGLOBAL;
  305. // Get the parse string
  306. hRes = pdtobj->GetData(&formatetc, &stgmedium);
  307. if (SUCCEEDED(hRes))
  308. {
  309. LPTSTR pszURLData = (LPTSTR)GlobalLock(stgmedium.hGlobal);
  310. if (pszURLData) {
  311. TCHAR szPath[MAX_PATH];
  312. SHFILEINFO sfi;
  313. int cFiles, i;
  314. HDROP hDrop = (HDROP)stgmedium.hGlobal;
  315. hRes = S_FALSE;
  316. cFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
  317. for (i = 0; i < cFiles; i ++) {
  318. DragQueryFile(hDrop, i, szPath, ARRAYSIZE(szPath));
  319. // defaults...
  320. StrCpyN(name, szPath, MAX_NAME_QUICKLINK);
  321. if (SHGetFileInfo(szPath, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME))
  322. StrCpyN(name, sfi.szDisplayName, MAX_NAME_QUICKLINK);
  323. if (SHGetFileInfo(szPath, 0, &sfi, sizeof(sfi),SHGFI_ATTRIBUTES)
  324. && (sfi.dwAttributes & SFGAO_LINK))
  325. {
  326. if (SUCCEEDED(_GetURLTarget(szPath, url, INTERNET_MAX_URL_LENGTH)))
  327. {
  328. TraceMsg(TF_SUBSFOLDER, "URL: %s, Name: %s", url, name);
  329. // If we just want to see whether there is some urls
  330. // here, we can break now.
  331. if (!bSubscribe)
  332. {
  333. if ((IsHTTPPrefixed(url)) &&
  334. (!SHRestricted2(REST_NoAddingSubscriptions, url, 0)))
  335. {
  336. hRes = S_OK;
  337. }
  338. break;
  339. }
  340. hRes = ScheduleDefault(url, name);
  341. }
  342. }
  343. }
  344. GlobalUnlock(stgmedium.hGlobal);
  345. if (bSubscribe)
  346. hRes = S_OK;
  347. } else
  348. hRes = S_FALSE;
  349. ReleaseStgMedium(&stgmedium);
  350. }
  351. return hRes;
  352. }
  353. // Takes a variety of inputs and returns a string for drop targets.
  354. // szUrl: the URL
  355. // szName: the name (for quicklinks and the confo dialog boxes)
  356. // returns: NOERROR if succeeded
  357. //
  358. HRESULT _GetURLData(IDataObject *pdtobj, int iDropType, TCHAR *pszUrl, TCHAR *pszName)
  359. {
  360. HRESULT hRes = NOERROR;
  361. STGMEDIUM stgmedium;
  362. FORMATETC formatetc;
  363. *pszName = 0;
  364. *pszUrl = 0;
  365. switch (iDropType)
  366. {
  367. case CITBDTYPE_URL:
  368. formatetc.cfFormat = (CLIPFORMAT) RegisterClipboardFormat(CFSTR_SHELLURL);
  369. break;
  370. case CITBDTYPE_TEXT:
  371. formatetc.cfFormat = CF_TEXT;
  372. break;
  373. default:
  374. return E_UNEXPECTED;
  375. }
  376. formatetc.ptd = NULL;
  377. formatetc.dwAspect = DVASPECT_CONTENT;
  378. formatetc.lindex = -1;
  379. formatetc.tymed = TYMED_HGLOBAL;
  380. // Get the parse string
  381. hRes = pdtobj->GetData(&formatetc, &stgmedium);
  382. if (SUCCEEDED(hRes))
  383. {
  384. LPTSTR pszURLData = (LPTSTR)GlobalLock(stgmedium.hGlobal);
  385. if (pszURLData)
  386. {
  387. if (iDropType == CITBDTYPE_URL)
  388. {
  389. STGMEDIUM stgmediumFGD;
  390. // defaults
  391. StrCpyN(pszUrl, pszURLData, INTERNET_MAX_URL_LENGTH);
  392. StrCpyN(pszName, pszURLData, MAX_NAME_QUICKLINK);
  393. formatetc.cfFormat = (CLIPFORMAT) RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
  394. if (SUCCEEDED(pdtobj->GetData(&formatetc, &stgmediumFGD)))
  395. {
  396. FILEGROUPDESCRIPTOR *pfgd = (FILEGROUPDESCRIPTOR *)GlobalLock(stgmediumFGD.hGlobal);
  397. if (pfgd)
  398. {
  399. TCHAR szPath[MAX_PATH];
  400. StrCpyN(szPath, pfgd->fgd[0].cFileName, ARRAYSIZE(szPath));
  401. PathRemoveExtension(szPath);
  402. StrCpyN(pszName, szPath, MAX_NAME_QUICKLINK);
  403. GlobalUnlock(stgmediumFGD.hGlobal);
  404. }
  405. ReleaseStgMedium(&stgmediumFGD);
  406. }
  407. }
  408. else if (iDropType == CITBDTYPE_TEXT)
  409. {
  410. if (PathIsURL(pszURLData)) {
  411. StrCpyN(pszUrl, pszURLData, INTERNET_MAX_URL_LENGTH);
  412. StrCpyN(pszName, pszURLData, MAX_NAME_QUICKLINK);
  413. } else
  414. hRes = E_FAIL;
  415. }
  416. GlobalUnlock(stgmedium.hGlobal);
  417. }
  418. ReleaseStgMedium(&stgmedium);
  419. }
  420. if (SUCCEEDED(hRes))
  421. {
  422. if (!IsHTTPPrefixed(pszUrl) || SHRestricted2(REST_NoAddingSubscriptions, pszUrl, 0))
  423. {
  424. hRes = E_FAIL;
  425. }
  426. }
  427. return hRes;
  428. }
  429. HRESULT ScheduleDefault(LPCTSTR url, LPCTSTR name)
  430. {
  431. if (!IsHTTPPrefixed(url))
  432. return E_INVALIDARG;
  433. ISubscriptionMgr * pSub= NULL;
  434. HRESULT hr = CoInitialize(NULL);
  435. RETURN_ON_FAILURE(hr);
  436. hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
  437. IID_ISubscriptionMgr, (void **)&pSub);
  438. CoUninitialize();
  439. RETURN_ON_FAILURE(hr);
  440. ASSERT(pSub);
  441. BSTR bstrURL = NULL, bstrName = NULL;
  442. hr = CreateBSTRFromTSTR(&bstrURL, url);
  443. if (S_OK == hr)
  444. hr = CreateBSTRFromTSTR(&bstrName, name);
  445. // We need a perfectly valid structure.
  446. SUBSCRIPTIONINFO subInfo;
  447. ZeroMemory((void *)&subInfo, sizeof (SUBSCRIPTIONINFO));
  448. subInfo.cbSize = sizeof(SUBSCRIPTIONINFO);
  449. if (S_OK == hr)
  450. hr = pSub->CreateSubscription(NULL, bstrURL, bstrName,
  451. CREATESUBS_NOUI, SUBSTYPE_URL, &subInfo);
  452. SAFERELEASE(pSub);
  453. SAFEFREEBSTR(bstrURL);
  454. SAFEFREEBSTR(bstrName);
  455. if (FAILED(hr)) {
  456. TraceMsg(TF_ALWAYS, "Failed to add default object.");
  457. TraceMsg(TF_ALWAYS, " hr = 0x%x\n", hr);
  458. return (FAILED(hr))?hr:E_FAIL;
  459. } else if (hr == S_FALSE) {
  460. TraceMsg(TF_SUBSFOLDER, "%s(%s) is already there.", url, name);
  461. return hr;
  462. }
  463. return S_OK;
  464. }