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.

480 lines
12 KiB

  1. #include "priv.h"
  2. #include "ishcut.h"
  3. #include "assocurl.h"
  4. #include "shlwapi.h"
  5. #include "resource.h"
  6. #include "shlguid.h"
  7. STDMETHODIMP Intshcut::QueryStatus(
  8. const GUID *pguidCmdGroup,
  9. ULONG cCmds,
  10. MSOCMD rgCmds[],
  11. MSOCMDTEXT *pcmdtext
  12. )
  13. {
  14. return E_NOTIMPL;
  15. }
  16. struct SHORTCUT_ICON_PARAMS
  17. {
  18. WCHAR *pwszFileName;
  19. WCHAR *pwszShortcutUrl;
  20. BSTR bstrIconUrl;
  21. ~SHORTCUT_ICON_PARAMS()
  22. {
  23. if(pwszFileName)
  24. {
  25. LocalFree(pwszFileName);
  26. pwszFileName = NULL;
  27. }
  28. if(bstrIconUrl)
  29. {
  30. SysFreeString(bstrIconUrl);
  31. bstrIconUrl = NULL;
  32. }
  33. if(pwszShortcutUrl)
  34. {
  35. SHFree(pwszShortcutUrl);
  36. pwszShortcutUrl = NULL;
  37. }
  38. }
  39. };
  40. const WCHAR wszDefaultShortcutIconName[] = ISHCUT_DEFAULT_FAVICONW;
  41. const WCHAR wszDefaultShortcutIconNameAtRoot[] = ISHCUT_DEFAULT_FAVICONATROOTW;
  42. extern const LARGE_INTEGER c_li0 ;
  43. VOID
  44. GetIconUrlFromLinkTag(
  45. IHTMLDocument2* pHTMLDocument,
  46. BSTR *pbstrIconUrl
  47. )
  48. {
  49. HRESULT hres;
  50. IHTMLLinkElement *pLink = NULL;
  51. hres = SearchForElementInHead(pHTMLDocument, OLESTR("REL"), OLESTR("SHORTCUT ICON"), IID_IHTMLLinkElement, (LPUNKNOWN *)&pLink);
  52. if(S_OK == hres)
  53. {
  54. hres = pLink->get_href(pbstrIconUrl);
  55. pLink->Release();
  56. }
  57. }
  58. BOOL SetIconForShortcut(
  59. WCHAR *pwszIconUrl,
  60. INamedPropertyBag *pNamedBag
  61. )
  62. {
  63. // Do it synchronously on this thread
  64. BOOL fRet = FALSE;
  65. WCHAR wszCacheFileName[MAX_PATH];
  66. HRESULT hr;
  67. ASSERT(pNamedBag);
  68. hr = URLDownloadToCacheFileW(NULL, pwszIconUrl, wszCacheFileName, sizeof(wszCacheFileName), NULL, NULL);
  69. if(S_OK == hr)
  70. {
  71. // 77657 security bug: we must not call LoadImage because the Win9x version can
  72. // crash with buffer overrun if given a corrupt icon. ExtractIcon helps validate the file
  73. // to prevent that specific crash.
  74. HICON hIcon = ExtractIcon(g_hinst, wszCacheFileName, 0);
  75. if(hIcon) // It is really an Icon
  76. {
  77. // Make this icon sticky in cache
  78. SetUrlCacheEntryGroupW(pwszIconUrl, INTERNET_CACHE_GROUP_ADD,
  79. CACHEGROUP_ID_BUILTIN_STICKY, NULL, 0, NULL);
  80. DestroyIcon(hIcon);
  81. // get the file - set the icon and return
  82. fRet = TRUE; // We Got the icon file - even if we are unable set it
  83. // Store this url away in the shortcut file
  84. PROPSPEC rgpropspec[2];
  85. PROPVARIANT rgpropvar[2];
  86. PROPVARIANT var;
  87. LBSTR::CString strUrl;
  88. if ( pwszIconUrl )
  89. {
  90. strUrl = pwszIconUrl;
  91. }
  92. else
  93. {
  94. strUrl.Empty();
  95. }
  96. var.vt = VT_BSTR;
  97. var.bstrVal = strUrl;
  98. hr = pNamedBag->WritePropertyNPB(ISHCUT_INISTRING_SECTIONW, ISHCUT_INISTRING_ICONFILEW,
  99. &var);
  100. if ( S_OK == hr )
  101. {
  102. LBSTR::CString strIndex;
  103. strIndex = L"1";
  104. var.vt = VT_BSTR;
  105. var.bstrVal = strIndex;
  106. hr = pNamedBag->WritePropertyNPB(ISHCUT_INISTRING_SECTIONW, ISHCUT_INISTRING_ICONINDEXW,
  107. &var);
  108. }
  109. // Update the intsite database - whether or not the
  110. // shortcut file was updated. This is because we need to
  111. // ensure that the intsite db is updated even if the shortcut file name is not known
  112. IPropertySetStorage *ppropsetstg;
  113. IPropertyStorage *ppropstg;
  114. rgpropspec[0].ulKind = PRSPEC_PROPID;
  115. rgpropspec[0].propid = PID_INTSITE_ICONINDEX;
  116. rgpropspec[1].ulKind = PRSPEC_PROPID;
  117. rgpropspec[1].propid = PID_INTSITE_ICONFILE;
  118. rgpropvar[0].vt = VT_I4;
  119. rgpropvar[0].lVal = 1;
  120. rgpropvar[1].vt = VT_LPWSTR;
  121. rgpropvar[1].pwszVal = pwszIconUrl;
  122. hr = pNamedBag->QueryInterface(IID_IPropertySetStorage,(LPVOID *)&ppropsetstg);
  123. if(SUCCEEDED(hr))
  124. {
  125. hr = ppropsetstg->Open(FMTID_InternetSite, STGM_READWRITE, &ppropstg);
  126. ppropsetstg->Release();
  127. }
  128. if(SUCCEEDED(hr))
  129. {
  130. hr = ppropstg->WriteMultiple(2, rgpropspec, rgpropvar, 0);
  131. ppropstg->Commit(STGC_DEFAULT);
  132. ppropstg->Release();
  133. }
  134. }
  135. }
  136. return fRet;
  137. }
  138. HRESULT PreUpdateShortcutIcon(IUniformResourceLocatorW *purlW, LPTSTR pszHashItem, int* piIndex,
  139. UINT* puFlags, int* piImageIndex, LPWSTR *ppwszURL)
  140. {
  141. ASSERT(pszHashItem);
  142. ASSERT(piIndex);
  143. ASSERT(puFlags);
  144. ASSERT(piImageIndex);
  145. HRESULT hr;
  146. ASSERT(purlW);
  147. if(purlW)
  148. {
  149. hr = purlW->GetURL(ppwszURL);
  150. if(S_OK == hr)
  151. {
  152. hr = GetGenericURLIcon(pszHashItem, MAX_PATH, piIndex);
  153. if (SUCCEEDED(hr))
  154. {
  155. SHFILEINFO fi = {0};
  156. if (SHGetFileInfo(pszHashItem, 0, &fi, sizeof(SHFILEINFO),
  157. SHGFI_SYSICONINDEX))
  158. {
  159. *piImageIndex = fi.iIcon;
  160. }
  161. else
  162. {
  163. *piImageIndex = -1;
  164. }
  165. }
  166. }
  167. }
  168. else
  169. {
  170. hr = E_INVALIDARG;
  171. }
  172. return hr;
  173. }
  174. DWORD
  175. DownloadAndSetIconForShortCutThreadProc(
  176. LPVOID pIn
  177. )
  178. {
  179. HINSTANCE hShdocvw = LoadLibrary(TEXT("shdocvw.dll"));
  180. SHORTCUT_ICON_PARAMS *pParams = (SHORTCUT_ICON_PARAMS *)pIn;
  181. WCHAR *pwszShortcutFilePath = pParams->pwszFileName;
  182. WCHAR *pwszIconUrl = pParams->bstrIconUrl;
  183. WCHAR wszFullUrl[MAX_URL_STRING];
  184. LPWSTR pwszBaseUrl = NULL;
  185. DWORD cchFullUrlSize = ARRAYSIZE(wszFullUrl);
  186. TCHAR szHash[MAX_PATH];
  187. IPersistFile * ppf = NULL;
  188. BOOL fRet = FALSE;
  189. INT iImageIndex;
  190. INT iIconIndex;
  191. UINT uFlags = 0;
  192. HRESULT hr;
  193. IUniformResourceLocatorW *purlW = NULL;
  194. HRESULT hresCoInit = E_FAIL;
  195. hresCoInit = CoInitialize(NULL);
  196. ASSERT(hShdocvw);
  197. hr = CoCreateInstance(CLSID_InternetShortcut, NULL,
  198. CLSCTX_INPROC_SERVER,
  199. IID_IUniformResourceLocatorW, (LPVOID *)&purlW);
  200. ASSERT(purlW);
  201. if((S_OK == hr) && purlW)
  202. {
  203. if(S_OK == hr)
  204. {
  205. if(pwszShortcutFilePath)
  206. {
  207. hr = purlW->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
  208. if(S_OK == hr)
  209. {
  210. ASSERT(ppf);
  211. hr = ppf->Load(pwszShortcutFilePath, STGM_READWRITE);
  212. }
  213. }
  214. else if(pParams->pwszShortcutUrl)
  215. {
  216. // Use the URL to init the shortcut
  217. hr = purlW->SetURL(pParams->pwszShortcutUrl, IURL_SETURL_FL_GUESS_PROTOCOL);
  218. }
  219. else
  220. {
  221. hr = E_FAIL;
  222. // Can't create an object and init it
  223. }
  224. }
  225. }
  226. if((S_OK == hr) && (purlW))
  227. {
  228. hr = PreUpdateShortcutIcon(purlW, szHash, &iIconIndex, &uFlags, &iImageIndex, (LPWSTR *)&pwszBaseUrl);
  229. INamedPropertyBag *pNamedBag = NULL;
  230. hr = purlW->QueryInterface(IID_INamedPropertyBag,(LPVOID *)&pNamedBag);
  231. if((S_OK == hr) && (pNamedBag))
  232. {
  233. if(pwszIconUrl)
  234. {
  235. WCHAR *pwszIconFullUrl;
  236. if(pwszBaseUrl)
  237. {
  238. hr = UrlCombineW(pwszBaseUrl, pwszIconUrl, wszFullUrl, &cchFullUrlSize, 0);
  239. ASSERT(S_OK == hr);
  240. if(SUCCEEDED(hr))
  241. {
  242. pwszIconFullUrl = wszFullUrl;
  243. }
  244. }
  245. else
  246. {
  247. pwszIconFullUrl = pwszIconUrl; // try it as it is
  248. }
  249. fRet = SetIconForShortcut( pwszIconFullUrl, pNamedBag);
  250. }
  251. if((FALSE == fRet) && (pwszBaseUrl))
  252. {
  253. hr = UrlCombineW(pwszBaseUrl, wszDefaultShortcutIconNameAtRoot, wszFullUrl, &cchFullUrlSize, 0);
  254. fRet = SetIconForShortcut(wszFullUrl, pNamedBag);
  255. }
  256. pNamedBag->Release();
  257. }
  258. }
  259. if(fRet)
  260. {
  261. SHUpdateImage(szHash, iIconIndex, uFlags, iImageIndex);
  262. }
  263. if(ppf)
  264. {
  265. ppf->Save(NULL, FALSE); // Save off Icon related stuff
  266. ppf->Release();
  267. }
  268. if(purlW)
  269. purlW->Release();
  270. if(pParams)
  271. delete pParams;
  272. if(pwszBaseUrl)
  273. SHFree(pwszBaseUrl);
  274. if(SUCCEEDED(hresCoInit))
  275. CoUninitialize();
  276. //FreeLibraryAndExitThread(hShdocvw); -- Need a FreeLibraryAndExitThread for thread pools
  277. return fRet;
  278. }
  279. STDMETHODIMP Intshcut::_DoIconDownload()
  280. {
  281. SHORTCUT_ICON_PARAMS *pIconParams;
  282. BOOL fThreadStarted = FALSE;
  283. HRESULT hr = S_OK;
  284. pIconParams = new SHORTCUT_ICON_PARAMS;
  285. if(pIconParams)
  286. {
  287. if(_punkSite)
  288. {
  289. IServiceProvider *psp;
  290. hr = _punkSite->QueryInterface(IID_IServiceProvider, (LPVOID *)&psp);
  291. if(SUCCEEDED(hr))
  292. {
  293. IWebBrowser2 *pwb=NULL;
  294. hr = psp->QueryService(SID_SHlinkFrame, IID_IWebBrowser2, (LPVOID *)&pwb);
  295. if(SUCCEEDED(hr))
  296. {
  297. IDispatch *pdisp = NULL;
  298. ASSERT(pwb);
  299. hr = pwb->get_Document(&pdisp);
  300. if(pdisp)
  301. {
  302. IHTMLDocument2 *pHTMLDocument;
  303. ASSERT(SUCCEEDED(hr));
  304. hr = pdisp->QueryInterface(IID_IHTMLDocument2, (void **)(&pHTMLDocument));
  305. if(SUCCEEDED(hr))
  306. {
  307. ASSERT(pHTMLDocument);
  308. GetIconUrlFromLinkTag(pHTMLDocument, &(pIconParams->bstrIconUrl));
  309. pHTMLDocument->Release();
  310. }
  311. pdisp->Release();
  312. }
  313. pwb->Release();
  314. }
  315. psp->Release();
  316. }
  317. }
  318. if(m_pszFile)
  319. {
  320. pIconParams->pwszFileName = StrDupW(m_pszFile);
  321. }
  322. // Now fill in the URL of the shortcut
  323. hr = GetURLW(&(pIconParams->pwszShortcutUrl));
  324. ASSERT(SUCCEEDED(hr));
  325. if(S_OK == hr)
  326. {
  327. fThreadStarted = SHQueueUserWorkItem(DownloadAndSetIconForShortCutThreadProc,
  328. (LPVOID)(pIconParams),
  329. 0,
  330. (DWORD_PTR)NULL,
  331. (DWORD_PTR *)NULL,
  332. "shdocvw.dll",
  333. 0
  334. );
  335. }
  336. }
  337. if(FALSE == fThreadStarted)
  338. {
  339. if(pIconParams)
  340. {
  341. delete pIconParams;
  342. }
  343. }
  344. return fThreadStarted ? S_OK : E_FAIL;
  345. }
  346. STDMETHODIMP Intshcut::Exec(
  347. const GUID *pguidCmdGroup,
  348. DWORD nCmdID,
  349. DWORD nCmdexecopt,
  350. VARIANTARG *pvarargIn,
  351. VARIANTARG *pvarargOut
  352. )
  353. {
  354. HRESULT hres = S_OK;
  355. if (pguidCmdGroup && IsEqualGUID(CGID_ShortCut, *pguidCmdGroup))
  356. {
  357. switch(nCmdID)
  358. {
  359. case ISHCUTCMDID_DOWNLOADICON:
  360. {
  361. DWORD dwFlags = 0;
  362. BOOL fFetch = TRUE;
  363. WCHAR *pwszUrl;
  364. // Don't do it for FTP shortcuts
  365. if(SUCCEEDED(GetURLW(&pwszUrl)))
  366. {
  367. if((URL_SCHEME_FTP == GetUrlSchemeW(pwszUrl)))
  368. fFetch = FALSE;
  369. SHFree(pwszUrl);
  370. }
  371. if(fFetch && (InternetGetConnectedState(&dwFlags, 0)))
  372. hres = _DoIconDownload();
  373. }
  374. break;
  375. default:
  376. break;
  377. }
  378. }
  379. return hres;
  380. }