Leaked source code of windows server 2003
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.

540 lines
15 KiB

  1. #include "private.h"
  2. #include "offl_cpp.h"
  3. #include "subsmgrp.h"
  4. HRESULT _GetURLData(IDataObject *pdtobj, int iDropType, TCHAR *pszUrl, UINT cchUrl, TCHAR *pszName, UINT cchName);
  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,ARRAYSIZE(url),name, ARRAYSIZE(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,ARRAYSIZE(url),name, ARRAYSIZE(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, ARRAYSIZE(url), name, ARRAYSIZE(name));
  211. if (FAILED(hr) && m_fHasTEXT)
  212. hr = _GetURLData(pDataObj, CITBDTYPE_TEXT, url, ARRAYSIZE(url), name, ARRAYSIZE(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. StrCatBuff(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. return CLSIDFromString(szCLSID, pclsid);
  242. }
  243. }
  244. return E_FAIL;
  245. }
  246. // get the target of a shortcut. this uses IShellLink which
  247. // Internet Shortcuts (.URL) and Shell Shortcuts (.LNK) support so
  248. // it should work generally
  249. //
  250. HRESULT _GetURLTarget(LPCTSTR pszPath, LPTSTR pszTarget, UINT cch)
  251. {
  252. IShellLink *psl;
  253. HRESULT hr = E_FAIL;
  254. CLSID clsid;
  255. if (FAILED(_CLSIDFromExtension(PathFindExtension(pszPath), &clsid)))
  256. clsid = CLSID_ShellLink; // assume it's a shell link
  257. hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&psl);
  258. if (SUCCEEDED(hr))
  259. {
  260. IPersistFile *ppf;
  261. hr = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
  262. if (SUCCEEDED(hr))
  263. {
  264. hr = ppf->Load(pszPath, 0);
  265. ppf->Release();
  266. }
  267. if (SUCCEEDED(hr)) {
  268. IUniformResourceLocator * purl;
  269. hr = psl->QueryInterface(IID_IUniformResourceLocator,(void**)&purl);
  270. if (SUCCEEDED(hr))
  271. purl->Release();
  272. }
  273. if (SUCCEEDED(hr))
  274. hr = psl->GetPath(pszTarget, cch, NULL, SLGP_UNCPRIORITY);
  275. psl->Release();
  276. }
  277. return hr;
  278. }
  279. HRESULT _ConvertHDROPData(IDataObject *pdtobj, BOOL bSubscribe)
  280. {
  281. HRESULT hRes = NOERROR;
  282. STGMEDIUM stgmedium;
  283. FORMATETC formatetc;
  284. TCHAR url[INTERNET_MAX_URL_LENGTH];
  285. TCHAR name[MAX_NAME_QUICKLINK];
  286. name[0] = 0;
  287. url[0] = 0;
  288. formatetc.cfFormat = CF_HDROP;
  289. formatetc.ptd = NULL;
  290. formatetc.dwAspect = DVASPECT_CONTENT;
  291. formatetc.lindex = -1;
  292. formatetc.tymed = TYMED_HGLOBAL;
  293. // Get the parse string
  294. hRes = pdtobj->GetData(&formatetc, &stgmedium);
  295. if (SUCCEEDED(hRes))
  296. {
  297. LPTSTR pszURLData = (LPTSTR)GlobalLock(stgmedium.hGlobal);
  298. if (pszURLData) {
  299. TCHAR szPath[MAX_PATH];
  300. SHFILEINFO sfi;
  301. int cFiles, i;
  302. HDROP hDrop = (HDROP)stgmedium.hGlobal;
  303. hRes = S_FALSE;
  304. cFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
  305. for (i = 0; i < cFiles; i ++) {
  306. DragQueryFile(hDrop, i, szPath, ARRAYSIZE(szPath));
  307. // defaults...
  308. StrCpyN(name, szPath, ARRAYSIZE(name));
  309. if (SHGetFileInfo(szPath, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME))
  310. StrCpyN(name, sfi.szDisplayName, ARRAYSIZE(name));
  311. if (SHGetFileInfo(szPath, 0, &sfi, sizeof(sfi),SHGFI_ATTRIBUTES)
  312. && (sfi.dwAttributes & SFGAO_LINK))
  313. {
  314. if (SUCCEEDED(_GetURLTarget(szPath, url, INTERNET_MAX_URL_LENGTH)))
  315. {
  316. TraceMsg(TF_SUBSFOLDER, "URL: %s, Name: %s", url, name);
  317. // If we just want to see whether there is some urls
  318. // here, we can break now.
  319. if (!bSubscribe)
  320. {
  321. if ((IsHTTPPrefixed(url)) &&
  322. (!SHRestricted2(REST_NoAddingSubscriptions, url, 0)))
  323. {
  324. hRes = S_OK;
  325. }
  326. break;
  327. }
  328. hRes = ScheduleDefault(url, name);
  329. }
  330. }
  331. }
  332. GlobalUnlock(stgmedium.hGlobal);
  333. if (bSubscribe)
  334. hRes = S_OK;
  335. } else
  336. hRes = S_FALSE;
  337. ReleaseStgMedium(&stgmedium);
  338. }
  339. return hRes;
  340. }
  341. // Takes a variety of inputs and returns a string for drop targets.
  342. // szUrl: the URL
  343. // szName: the name (for quicklinks and the confo dialog boxes)
  344. // returns: NOERROR if succeeded
  345. //
  346. HRESULT _GetURLData(IDataObject *pdtobj, int iDropType, TCHAR *pszUrl, UINT cchUrl, TCHAR *pszName, UINT cchName)
  347. {
  348. HRESULT hRes = NOERROR;
  349. STGMEDIUM stgmedium;
  350. FORMATETC formatetc;
  351. *pszName = 0;
  352. *pszUrl = 0;
  353. switch (iDropType)
  354. {
  355. case CITBDTYPE_URL:
  356. formatetc.cfFormat = (CLIPFORMAT) RegisterClipboardFormat(CFSTR_SHELLURL);
  357. break;
  358. case CITBDTYPE_TEXT:
  359. formatetc.cfFormat = CF_TEXT;
  360. break;
  361. default:
  362. return E_UNEXPECTED;
  363. }
  364. formatetc.ptd = NULL;
  365. formatetc.dwAspect = DVASPECT_CONTENT;
  366. formatetc.lindex = -1;
  367. formatetc.tymed = TYMED_HGLOBAL;
  368. // Get the parse string
  369. hRes = pdtobj->GetData(&formatetc, &stgmedium);
  370. if (SUCCEEDED(hRes))
  371. {
  372. LPTSTR pszURLData = (LPTSTR)GlobalLock(stgmedium.hGlobal);
  373. if (pszURLData)
  374. {
  375. if (iDropType == CITBDTYPE_URL)
  376. {
  377. STGMEDIUM stgmediumFGD;
  378. // defaults
  379. StrCpyN(pszUrl, pszURLData, cchUrl);
  380. StrCpyN(pszName, pszURLData, cchName);
  381. formatetc.cfFormat = (CLIPFORMAT) RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
  382. if (SUCCEEDED(pdtobj->GetData(&formatetc, &stgmediumFGD)))
  383. {
  384. FILEGROUPDESCRIPTOR *pfgd = (FILEGROUPDESCRIPTOR *)GlobalLock(stgmediumFGD.hGlobal);
  385. if (pfgd)
  386. {
  387. TCHAR szPath[MAX_PATH];
  388. StrCpyN(szPath, pfgd->fgd[0].cFileName, ARRAYSIZE(szPath));
  389. PathRemoveExtension(szPath);
  390. StrCpyN(pszName, szPath, cchName);
  391. GlobalUnlock(stgmediumFGD.hGlobal);
  392. }
  393. ReleaseStgMedium(&stgmediumFGD);
  394. }
  395. }
  396. else if (iDropType == CITBDTYPE_TEXT)
  397. {
  398. if (PathIsURL(pszURLData)) {
  399. StrCpyN(pszUrl, pszURLData, cchUrl);
  400. StrCpyN(pszName, pszURLData, cchName);
  401. } else
  402. hRes = E_FAIL;
  403. }
  404. GlobalUnlock(stgmedium.hGlobal);
  405. }
  406. ReleaseStgMedium(&stgmedium);
  407. }
  408. if (SUCCEEDED(hRes))
  409. {
  410. if (!IsHTTPPrefixed(pszUrl) || SHRestricted2(REST_NoAddingSubscriptions, pszUrl, 0))
  411. {
  412. hRes = E_FAIL;
  413. }
  414. }
  415. return hRes;
  416. }
  417. HRESULT ScheduleDefault(LPCTSTR url, LPCTSTR name)
  418. {
  419. if (!IsHTTPPrefixed(url))
  420. return E_INVALIDARG;
  421. ISubscriptionMgr * pSub= NULL;
  422. HRESULT hr = CoInitialize(NULL);
  423. RETURN_ON_FAILURE(hr);
  424. hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER,
  425. IID_ISubscriptionMgr, (void **)&pSub);
  426. CoUninitialize();
  427. RETURN_ON_FAILURE(hr);
  428. ASSERT(pSub);
  429. BSTR bstrURL = NULL, bstrName = NULL;
  430. hr = CreateBSTRFromTSTR(&bstrURL, url);
  431. if (S_OK == hr)
  432. hr = CreateBSTRFromTSTR(&bstrName, name);
  433. // We need a perfectly valid structure.
  434. SUBSCRIPTIONINFO subInfo;
  435. ZeroMemory((void *)&subInfo, sizeof (subInfo));
  436. subInfo.cbSize = sizeof(SUBSCRIPTIONINFO);
  437. if (S_OK == hr)
  438. hr = pSub->CreateSubscription(NULL, bstrURL, bstrName,
  439. CREATESUBS_NOUI, SUBSTYPE_URL, &subInfo);
  440. SAFERELEASE(pSub);
  441. SAFEFREEBSTR(bstrURL);
  442. SAFEFREEBSTR(bstrName);
  443. if (FAILED(hr)) {
  444. TraceMsg(TF_ALWAYS, "Failed to add default object.");
  445. TraceMsg(TF_ALWAYS, " hr = 0x%x\n", hr);
  446. return (FAILED(hr))?hr:E_FAIL;
  447. } else if (hr == S_FALSE) {
  448. TraceMsg(TF_SUBSFOLDER, "%s(%s) is already there.", url, name);
  449. return hr;
  450. }
  451. return S_OK;
  452. }