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.

479 lines
13 KiB

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